/**
 @file ctc_asw_chip.c

 @author  Copyright (C) 2020 Centec Networks Inc.  All rights reserved.

 @date 2020-09-15

 @version v2.0

 The file contains all chip APIs
*/
/****************************************************************************
*
* Header Files
*
****************************************************************************/
#include "ctc_asw_common.h"
#include "ctc_asw_port.h"
#include "ctc_asw_chip.h"
#include "ctc_asw_interrupt.h"
#include "asw/include/drv_api.h"
#include "dal.h"
#include "ctc_acl.h"

/****************************************************************************
*]
* Defines and Macros
*
*****************************************************************************/
#define CTC_ASW_CPU_PORT_0 27
#define CTC_ASW_CPU_PORT_1 28
#define CTC_ASW_MAX_PHY_PORT_NUM (CTC_ASW_MAX_PHY_PORT+1)

#define CTC_ASW_CHIP_LED_FORCE_OFF      0
#define CTC_ASW_CHIP_LED_ON_RX_LINK     1
#define CTC_ASW_CHIP_LED_ON_TX_LINK     2
#define CTC_ASW_CHIP_LED_FORCE_ON       3

#define CTC_ASW_CHIP_LED_BLINK_OFF      0
#define CTC_ASW_CHIP_LED_BLINK_RX_ACT   1
#define CTC_ASW_CHIP_LED_BLINK_TX_ACT   2
#define CTC_ASW_CHIP_LED_BLINK_ON       3

#define CTC_ASW_CHIP_MAX_TIME_OUT       256

#define CTC_ASW_CHIP_MAX_GPIO_ID        7
#define CTC_ASW_CHIP_MAX_GPIO_VALUE     1

#define CTC_ASW_CHIP_PHY_MAX_SHIM 8
#define CTC_ASW_ACL_ENTRY_ARRAY_NUM 8
#define CTC_ASW_ACL_PER_SLICE_ENTRY_NUM 16
#define CTC_ASW_L2_ACL_SLICE_NUM  8
#define CTC_ASW_L2_ACL_SLICE_4  4
#define CTC_ASW_L2_ACL_SLICE_0  0
#define CTC_ASW_L2_MAC_LEN  6

/*datapath macro*/
#define CTC_ASW_CHIP_CORE_CLOCK 125000
#define CTC_ASW_MAX_PHY_NUM 8
#define CTC_ASW_MAX_SERDES_NUM 16
#define CTC_ASW_MAX_NORMAL_SERDES_NUM 8
#define CTC_ASW_MAX_DFE_MODE_NUM 3

#define CTC_ASW_SERDES_IS_PHY(serdes_id) \
    ((serdes_id) >= 8)

#define CTC_ASW_SERDES_IS_SOUTH_HSS(serdes_id) \
    ((serdes_id) < 4)

#define CTC_ASW_SERDES_IS_NORTH_HSS(serdes_id) \
    (((serdes_id) >= 4) && ((serdes_id) < 8))

#define CTC_ASW_SERDES_IS_CPU_MAC(serdes_id) \
    ((serdes_id) == 16)

#define CTC_ASW_SERDES_ADDRESS(serdes_id, address) \
    (address + ((serdes_id%2)*0x100))

enum ctc_asw_datapath_lport_type_e
{
    CTC_ASW_DATAPATH_NETWORK_PORT,
    CTC_ASW_DATAPATH_RSV_PORT
};
typedef enum ctc_asw_datapath_lport_type_e ctc_asw_datapath_lport_type_t;

struct ctc_asw_datapath_serdes_info_s
{
    uint8 mode;        /*pcs mode, refer to ctc_chip_serdes_mode_t*/
    uint8 port_num;  /*serdes port count  TMM lport & channel number*/
	uint16 lport;       /*chip local phy port*/
};
typedef struct ctc_asw_datapath_serdes_info_s   ctc_asw_datapath_serdes_info_t;

struct ctc_asw_datapath_lport_attr_s
{
    uint32 port_type:4;  /*refer to ctc_asw_datapath_lport_type_t */
    uint32 mac_id:5;
    uint32 speed_mode:5;  /*refer to ctc_port_speed_t, only usefull for network port*/
    uint32 pcs_mode:6; /*refer to ctc_chip_serdes_mode_t*/

    uint32 serdes_id:6;
	uint32 rsv:6;
};
typedef struct ctc_asw_datapath_lport_attr_s ctc_asw_datapath_lport_attr_t;

struct ctc_asw_datapath_master_s
{
    ctc_asw_datapath_serdes_info_t serdes_info[CTC_ASW_MAX_SERDES_NUM]; /* store hss and serdes info */
    ctc_asw_datapath_lport_attr_t port_attr[CTC_ASW_MAX_PHY_PORT_NUM];
    uint16 core_freq;
};
typedef struct ctc_asw_datapath_master_s ctc_asw_datapath_master_t;

struct ctc_asw_chip_master_s
{
    uint16 tpid;
    uint8 port_mdio_mapping_tbl[CTC_ASW_MAX_PHY_PORT_NUM];
    uint8 port_phy_mapping_tbl[CTC_ASW_MAX_PHY_PORT_NUM];
    uint8 port_phy_shim_idx[CTC_ASW_MAX_PHY_PORT_NUM];
    uint8 link_status[CTC_ASW_MAX_PHY_PORT_NUM];
    uint32 cpu_port;
    mac_addr_t cpu_mac_da;
    uint32 phy_shim_bitmap;
    ctc_chip_phy_shim_t phy_shim[CTC_ASW_CHIP_PHY_MAX_SHIM];
    sal_task_t* p_polling_task;
    uint16 acl_entry_bmp[CTC_ASW_ACL_ENTRY_ARRAY_NUM];
    uint8  acl_slice_cnt[CTC_ASW_ACL_ENTRY_ARRAY_NUM];
};
typedef struct ctc_asw_chip_master_s ctc_asw_chip_master_t;
/****************************************************************************
*
* Global and Declaration
*
*****************************************************************************/
extern dal_op_t g_dal_op;
ctc_asw_datapath_master_t datapath_master[CTC_MAX_LOCAL_CHIP_NUM]={0};
ctc_asw_chip_master_t chip_master[CTC_MAX_LOCAL_CHIP_NUM]={0};
sal_mutex_t* api_mutex[CTC_MAX_LOCAL_CHIP_NUM] = {NULL};
sal_mutex_t* mdio_mutex[CTC_MAX_LOCAL_CHIP_NUM] = {NULL};
/****************************************************************************
*
*  Functions
*
*****************************************************************************/
extern int32
_ctc_asw_mac_get_property(uint8 lchip, uint32 gport, ctc_port_property_t port_prop, uint32* p_value);
extern int32
_ctc_asw_mac_set_property(uint8 lchip, uint32 gport, ctc_port_property_t port_prop, uint32 value);
extern int32
_ctc_asw_port_set_acl_property(uint8 lchip, uint32 gport, ctc_acl_property_t* p_prop, uint8 is_inner);

int32
_ctc_asw_chip_check_acl_entry_id(uint8 lchip, uint32 entry_id)
{
    if (CTC_IS_BIT_SET(chip_master[lchip].acl_entry_bmp[entry_id >> 4], entry_id % CTC_ASW_ACL_PER_SLICE_ENTRY_NUM))
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

int32
_ctc_asw_chip_get_acl_entry_id(uint8 lchip, uint32* p_entry_id)
{
    int16 index = 0;
   
    for (index = CTC_ASW_L2_ACL_ENTRY_MAX; index >= 0; index--)
    {
        if (0 == CTC_IS_BIT_SET(chip_master[lchip].acl_entry_bmp[index >> 4], index % CTC_ASW_ACL_PER_SLICE_ENTRY_NUM))
        {
            break;
        }
    }
    if (index < 0)
    {
        return CTC_E_NO_RESOURCE;
    }
    *p_entry_id = index;

    return CTC_E_NONE;
}


int32
_ctc_asw_chip_set_acl_entry_id(uint8 lchip, uint32  entry_id, uint8 enable)
{
    int32 ret = CTC_E_NONE;
    uint8 slice_id = ((entry_id % CTC_ASW_L2_ACL_SLICE_NUM) >> 1) + ((entry_id > (CTC_ASW_L2_ACL_ENTRY_MAX >> 1))? CTC_ASW_L2_ACL_SLICE_4 : CTC_ASW_L2_ACL_SLICE_0);
    uint8 entry_offset = entry_id >> 4;
    ctc_acl_property_t prop;
    uint32 gport = 0;
    if (enable)
    {
        if (0 == chip_master[lchip].acl_slice_cnt[slice_id])
        {
            for (gport = 0; gport < CTC_ASW_MAX_PHY_PORT; gport++)
            {
                prop.acl_en = 1;
                prop.tcam_lkup_type = CTC_ACL_KEY_MAC;
                prop.acl_priority = slice_id + 1;
                CTC_ERROR_RETURN(_ctc_asw_port_set_acl_property(lchip, gport, &prop, 1));
            }
        }
        CTC_BIT_SET(chip_master[lchip].acl_entry_bmp[entry_offset], entry_id % CTC_ASW_ACL_PER_SLICE_ENTRY_NUM);
        chip_master[lchip].acl_slice_cnt[slice_id]++;
    }
    else
    {
        CTC_BIT_UNSET(chip_master[lchip].acl_entry_bmp[entry_offset], entry_id % CTC_ASW_ACL_PER_SLICE_ENTRY_NUM);
        chip_master[lchip].acl_slice_cnt[slice_id]--;
        if (0 == chip_master[lchip].acl_slice_cnt[slice_id])
        {
            for (gport = 0; gport < CTC_ASW_MAX_PHY_PORT; gport++)
            {
                prop.acl_en = 0;
                prop.tcam_lkup_type = CTC_ACL_KEY_MAC;
                prop.acl_priority = slice_id + 1;
                ret = _ctc_asw_port_set_acl_property(lchip, gport, &prop, 1);
            }
        }
    }
    return ret;
}

int32 
_ctc_asw_chip_find_entry(uint8 lchip, hw_mac_addr_t        hw_mac, uint16 fid, uint32* entry_id)
{
    uint32 cmd = 0;
    ds_t tmp_key = {0};
    ds_t tmp_mask = {0};
    mask_tbl_entry_t tcam_entry;
    hw_mac_addr_t   acl_hw_mac = {0};
    uint16 acl_fid = 0;
    int32 ret = CTC_E_NONE;
    int32 loop = 0;
    tcam_entry.data_entry = (uint32 *)&tmp_key;
    tcam_entry.mask_entry = (uint32 *)&tmp_mask;
    for (loop = CTC_ASW_L2_ACL_ENTRY_MAX; loop >= 0; loop--)
    {
        if(!CTC_IS_BIT_SET(chip_master[lchip].acl_entry_bmp[loop>>4], loop%CTC_ASW_ACL_PER_SLICE_ENTRY_NUM))
        {
            continue;
        }
        cmd = DRV_IOR(Key160MacView0_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_MASK_IOCTL(lchip, loop, cmd, &tcam_entry));
        acl_fid = GetKey160MacView0(V, stag_f, tmp_key);
        GetKey160MacView0(A,da_f,tmp_key,acl_hw_mac);
        if (sal_memcmp(hw_mac,acl_hw_mac,CTC_ASW_L2_MAC_LEN) == 0 && acl_fid == fid)
        {
            *entry_id = loop;
            return ret;
        }
    }
    if(loop < 0)
    {
        ret = CTC_E_INVALID_CONFIG;
    }
    return ret;
}

int32
_ctc_asw_chip_get_first_slice(uint8 lchip, uint8* p_slice_id)
{
    uint8 index = 0;

    for (index = 0; index < 8; index++)
    {
        if (chip_master[lchip].acl_slice_cnt[index] != 0)
        {
            break;
        }
    }
    *p_slice_id = index;
    return index? CTC_E_NONE : CTC_E_NO_RESOURCE;
}

#define ______DATAPATH_INTERNAL______
STATIC int32
_ctc_asw_chip_mdio_write(uint8 lchip, ctc_chip_mdio_type_t type, ctc_chip_mdio_para_t* p_para)
{
    int32 ret = 0;
    uint32 cmd = 0;
    uint32 mdio_cmd_done = 0;
    uint32 timeout = CTC_ASW_CHIP_MAX_TIME_OUT;
    ds_t ds;

    sal_memset(ds, 0, sizeof(ds));
    /* set MdioCfg */
    SetMdioCfg(V, mdioInDly_f, &ds, 0x1);
    SetMdioCfg(V, mdioMacPre_f, &ds, 0x1f);
    if(0 == p_para->bus)
    {
        /*config internal phy*/
        SetMdioCfg(V, mdioNetSel_f, &ds, 0x1);
	}
    else
    {
        /*config external phy*/
        SetMdioCfg(V, mdioNetSel_f, &ds, 0);
	}
    cmd = DRV_IOW(MdioCfg_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip,0,cmd,&ds);

    /* set mdio operation cmd */
    SetMdioCmd(V, phyAddCmd_f, &ds, p_para->phy_addr);
    SetMdioCmd(V, regAddCmd_f, &ds, p_para->reg);
    SetMdioCmd(V, opCodeCmd_f, &ds, 1);
    SetMdioCmd(V, dataCmd_f, &ds, p_para->value);
    cmd = DRV_IOW(MdioCmd_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    /* start write operation */
    SetMdioStart(V, startCmd_f, &ds, 1);
    cmd = DRV_IOW(MdioStart_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    /* check status done */
    cmd = DRV_IOR(MdioStatus_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip, 0, cmd, &ds);
    mdio_cmd_done = GetMdioStatus(V, mdioCmdDone_f, &ds);
    while ((mdio_cmd_done == 0) && (--timeout))
    {
        ret = ret?ret:DRV_IOCTL(lchip, 0, cmd, &ds);
        if (ret < 0)
        {
            return CTC_E_HW_FAIL;
        }
        mdio_cmd_done = GetMdioStatus(V, mdioCmdDone_f, &ds);
    }

    if (mdio_cmd_done == 0)
    {
        return CTC_E_HW_TIME_OUT;
    }

    return ret;
}

STATIC int32
_ctc_asw_chip_mdio_read(uint8 lchip, ctc_chip_mdio_type_t type, ctc_chip_mdio_para_t* p_para)
{
    int32 ret = 0;
    uint32 cmd = 0;
    uint32 mdio_cmd_done = 0;
    uint32 timeout = CTC_ASW_CHIP_MAX_TIME_OUT;
    ds_t ds;

    sal_memset(ds, 0, sizeof(ds));
    /* set MdioCfg */
    if(0 == p_para->bus)
    {
        /*config internal phy*/
        SetMdioCfg(V, mdioInDly_f, &ds, 0x1);
        SetMdioCfg(V, mdioMacPre_f, &ds, 0x1f);
        SetMdioCfg(V, mdioNetSel_f, &ds, 0x1);
	}
    else
    {
        /*config external phy*/
        SetMdioCfg(V, mdioInDly_f, &ds, 0x1);
        SetMdioCfg(V, mdioMacPre_f, &ds, 0x1f);
        SetMdioCfg(V, mdioNetSel_f, &ds, 0);
	}
    cmd = DRV_IOW(MdioCfg_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip,0,cmd,&ds);

    /* set mdio operation cmd */
    SetMdioCmd(V, phyAddCmd_f, &ds, p_para->phy_addr);
    SetMdioCmd(V, regAddCmd_f, &ds, p_para->reg);
    SetMdioCmd(V, opCodeCmd_f, &ds, 2);
    SetMdioCmd(V, dataCmd_f, &ds, p_para->value);
    cmd = DRV_IOW(MdioCmd_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    /* start write operation */
    SetMdioStart(V, startCmd_f, &ds, 1);
    cmd = DRV_IOW(MdioStart_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    /* check status done */
    cmd = DRV_IOR(MdioStatus_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip, 0, cmd, &ds);
    mdio_cmd_done = GetMdioStatus(V, mdioCmdDone_f, &ds);
    while ((mdio_cmd_done == 0) && (--timeout))
    {
        ret = DRV_IOCTL(lchip, 0, cmd, &ds);
        if (ret < 0)
        {
            return CTC_E_HW_FAIL;
        }
        mdio_cmd_done = GetMdioStatus(V, mdioCmdDone_f, &ds);
    }

    if (mdio_cmd_done == 0)
    {
        return CTC_E_HW_TIME_OUT;
    }

    /* read data */
    p_para->value = GetMdioStatus(V, mdioReadData_f, &ds);

    return ret;
}

STATIC int32
_ctc_asw_datapath_get_mac_id_with_gport(uint8 lchip, uint32 gport, uint8* p_mac_id)
{
    CTC_MAX_GPORT_CHECK(gport);

    *p_mac_id = datapath_master[lchip].port_attr[gport].mac_id;

    return CTC_E_NONE;
}

STATIC int32
_ctc_asw_datapath_get_serdes_info(uint8 lchip, uint16 serdes_id, ctc_asw_datapath_serdes_info_t** p_serdes)
{
    CTC_MAX_VALUE_CHECK(serdes_id, CTC_ASW_MAX_SERDES_NUM-1);
    *p_serdes = &datapath_master[lchip].serdes_info[serdes_id];

    return CTC_E_NONE;
}

STATIC int32
_ctc_asw_datapath_get_gport_with_serdes(uint8 lchip, uint16 serdes_id, uint32* p_gport, uint8* p_port_num)
{
    CTC_MAX_VALUE_CHECK(serdes_id, CTC_ASW_MAX_SERDES_NUM-1);
    if (CTC_CHIP_SERDES_NONE_MODE == datapath_master[lchip].serdes_info[serdes_id].mode)
    {
        return CTC_E_NOT_INIT;
    }
    *p_gport = datapath_master[lchip].serdes_info[serdes_id].lport;
    *p_port_num = datapath_master[lchip].serdes_info[serdes_id].port_num;
    return CTC_E_NONE;
}

STATIC int32
_ctc_asw_datapath_set_serdes_prbs_tx(uint8 lchip, ctc_chip_serdes_prbs_t* p_prbs)
{
    uint16 value16 = 0;
    if (0 == p_prbs->value)
    {
        value16 = 0;
    }
    else if (CTC_CHIP_SERDES_PRBS7_PLUS == p_prbs->polynome_type)
    {
        value16 = 0x8000;
    }
    else if (CTC_CHIP_SERDES_PRBS31_PLUS == p_prbs->polynome_type)
    {
        value16 = 0x8100;
    }
    else
    {
        return CTC_E_INVALID_PARAM;
    }
    CTC_ERROR_RETURN(_ctc_chip_serdes_write(lchip, p_prbs->serdes_id, CTC_ASW_SERDES_ADDRESS(p_prbs->serdes_id, 0x105), value16));

    return CTC_E_NONE;
}

STATIC int32
_ctc_asw_datapath_set_serdes_prbs_rx(uint8 lchip, ctc_chip_serdes_prbs_t* p_prbs)
{
    uint16 value16 = 0;
    uint8 serdes_id = p_prbs->serdes_id;

    if (0 == p_prbs->value)
    {
        CTC_ERROR_RETURN(_ctc_chip_serdes_write(lchip, serdes_id, CTC_ASW_SERDES_ADDRESS(serdes_id, 0x105), 0));
        return CTC_E_NONE;
    }
    else if (CTC_CHIP_SERDES_PRBS7_PLUS == p_prbs->polynome_type)
    {
        value16 = 0x4000;
    }
    else if (CTC_CHIP_SERDES_PRBS31_PLUS == p_prbs->polynome_type)
    {
        value16 = 0x4100;
    }
    else
    {
        return CTC_E_INVALID_PARAM;
    }
    CTC_ERROR_RETURN(_ctc_chip_serdes_write(lchip, serdes_id, CTC_ASW_SERDES_ADDRESS(serdes_id, 0x105), value16));
    sal_task_sleep(100);
    CTC_ERROR_RETURN(_ctc_chip_serdes_read(lchip, serdes_id, CTC_ASW_SERDES_ADDRESS(serdes_id, 0x108), &value16));
    /*if bit0 set 1, real time PRBS test synchronization status
    if bit1 set 1, PRBS test synchronization status, once the sync is lost, this bit will latch low, until it's been read out.*/
    p_prbs->value = (3==value16)?1:0;
    if (1 == value16)
    {
        CTC_ERROR_RETURN(_ctc_chip_serdes_read(lchip, serdes_id, CTC_ASW_SERDES_ADDRESS(serdes_id, 0x109), &value16));
        p_prbs->error_cnt = value16;
        CTC_ERROR_RETURN(_ctc_chip_serdes_read(lchip, serdes_id, CTC_ASW_SERDES_ADDRESS(serdes_id, 0x10a), &value16));
        p_prbs->error_cnt |= value16<<16;
    }
    return CTC_E_NONE;
}

STATIC int32
_ctc_asw_datapath_get_serdes_prbs_tx(uint8 lchip, ctc_chip_serdes_prbs_t* p_prbs)
{
    uint16 value16 = 0;

    CTC_ERROR_RETURN(_ctc_chip_serdes_read(lchip, p_prbs->serdes_id, CTC_ASW_SERDES_ADDRESS(p_prbs->serdes_id, 0x105), &value16));
    p_prbs->polynome_type = (value16&0x0100)?CTC_CHIP_SERDES_PRBS31_PLUS:CTC_CHIP_SERDES_PRBS7_PLUS;
    /*if this bit 15 set ,enable TX PRBS or self-defined pattern,*/
    p_prbs->value = (value16&0x8000)?1:0;
    return CTC_E_NONE;
}

STATIC int32
_ctc_asw_datapath_get_serdes_prbs_rx(uint8 lchip, ctc_chip_serdes_prbs_t* p_prbs)
{
    uint16 value16 = 0;
    uint8 serdes_id = p_prbs->serdes_id;

    CTC_ERROR_RETURN(_ctc_chip_serdes_read(lchip, serdes_id, CTC_ASW_SERDES_ADDRESS(serdes_id, 0x105), &value16));
    p_prbs->polynome_type = (value16&0x0100)?CTC_CHIP_SERDES_PRBS31_PLUS:CTC_CHIP_SERDES_PRBS7_PLUS;
    /*if this bit 14 set ,enable RX Bit Error Rate Test*/
    p_prbs->value = (value16&0x4000)?1:0;
    if (p_prbs->value)
    {
        CTC_ERROR_RETURN(_ctc_chip_serdes_read(lchip, serdes_id, CTC_ASW_SERDES_ADDRESS(serdes_id, 0x109), &value16));
        p_prbs->error_cnt = value16;
        CTC_ERROR_RETURN(_ctc_chip_serdes_read(lchip, serdes_id, CTC_ASW_SERDES_ADDRESS(serdes_id, 0x10a), &value16));
        p_prbs->error_cnt |= value16<<16;
    }

    return CTC_E_NONE;
}

STATIC int32
_ctc_asw_datapath_set_serdes_ffe(uint8 lchip, ctc_chip_serdes_ffe_t* p_ffe)
{
    uint16 value16 = 0;
    uint8 serdes_id = p_ffe->serdes_id;

    /*check ffe c2 and c3 value*/
    CTC_MAX_VALUE_CHECK(p_ffe->coefficient[2], 0xF);
    CTC_MAX_VALUE_CHECK(p_ffe->coefficient[3], 0x7);
    CTC_ERROR_RETURN(_ctc_chip_serdes_read(lchip, serdes_id, CTC_ASW_SERDES_ADDRESS(serdes_id, 0x1a1), &value16));
    value16 &= ~0xF000;
    value16 |= (p_ffe->coefficient[2]<<12); /*config main cursor*/
    value16 &= ~0x002E;
    value16 |= (p_ffe->coefficient[3]<<1); /*config post cursor*/
    value16 |= 0x0020;  /*enable post cursor*/
    CTC_ERROR_RETURN(_ctc_chip_serdes_write(lchip, serdes_id, CTC_ASW_SERDES_ADDRESS(serdes_id, 0x1a1), value16));
    /*0:0~10inch 1:>=10inch <20inch 2:>=20inch*/
    value16 = (p_ffe->trace_len == 1)?0x5510:((p_ffe->trace_len == 2)?0x510:0x5510);
    CTC_ERROR_RETURN(_ctc_chip_serdes_write(lchip, serdes_id, CTC_ASW_SERDES_ADDRESS(serdes_id, 0x1a3), value16));
    value16 = (p_ffe->trace_len == 1)?0x31:((p_ffe->trace_len == 2)?0x62:0x0);
    CTC_ERROR_RETURN(_ctc_chip_serdes_write(lchip, serdes_id, CTC_ASW_SERDES_ADDRESS(serdes_id, 0x1a6), value16));
    return CTC_E_NONE;
}


STATIC int32
_ctc_asw_datapath_get_serdes_ffe(uint8 lchip, ctc_chip_serdes_ffe_t* p_ffe)
{
    uint16 value16 = 0;
    
    CTC_ERROR_RETURN(_ctc_chip_serdes_read(lchip, p_ffe->serdes_id, CTC_ASW_SERDES_ADDRESS(p_ffe->serdes_id, 0x1a1), &value16));
    p_ffe->coefficient[0] = 0;
    p_ffe->coefficient[1] = 0;
    p_ffe->coefficient[2] = (value16 >>12) &0xF; /*bit12~15 main*/
    p_ffe->coefficient[3] = ((value16>>5)&0x1)? ((value16 >>1) &0x7):0; /*bit5 enable bit1~3 post*/

    /*0:0~10inch 1:>=10inch <20inch 2:>=20inch*/
    CTC_ERROR_RETURN(_ctc_chip_serdes_read(lchip, p_ffe->serdes_id, CTC_ASW_SERDES_ADDRESS(p_ffe->serdes_id, 0x1a6), &value16));
    p_ffe->trace_len = (value16 == 0x31)?1:((value16 == 0x62)?2:0);

    return CTC_E_NONE;
}
STATIC int32
_ctc_asw_datapath_set_serdes_dfe(uint8 lchip, ctc_chip_serdes_cfg_t* p_dfe)
{
    uint8 serdes_id = p_dfe->serdes_id;
    uint16 value1 = 0;
    uint16 value2 = 0;
    switch (p_dfe->value)
    {
        case 0:
            value1 = 0x5510;
            value2 = 0;
            break;
        case 1:
            value1 = 0x5510;
            value2 = 0x31;
            break;
        case 2:
            value1 = 0x510;
            value2 = 0x62;
            break;
        default:
            value1 = 0x5510;
            value2 = 0;
            break;
    }
    CTC_ERROR_RETURN(_ctc_chip_serdes_write(lchip, serdes_id, CTC_ASW_SERDES_ADDRESS(serdes_id, 0x1a3), value1));
    CTC_ERROR_RETURN(_ctc_chip_serdes_write(lchip, serdes_id, CTC_ASW_SERDES_ADDRESS(serdes_id, 0x1a6), value2));

    return CTC_E_NONE;
}

STATIC int32
_ctc_asw_datapath_get_serdes_dfe(uint8 lchip, ctc_chip_serdes_cfg_t* p_dfe)
{
    uint16 value1 = 0;
    uint16 value2 = 0;

    CTC_ERROR_RETURN(_ctc_chip_serdes_read(lchip, p_dfe->serdes_id, CTC_ASW_SERDES_ADDRESS(p_dfe->serdes_id, 0x1a3), &value1));
    CTC_ERROR_RETURN(_ctc_chip_serdes_read(lchip, p_dfe->serdes_id, CTC_ASW_SERDES_ADDRESS(p_dfe->serdes_id, 0x1a6), &value2));
    if (value1 == 0x5510 && value2 == 0)
    {
        p_dfe->value = 0;
    }
    else if (value1 == 0x5510 && value2 == 0x31)
    {
        p_dfe->value = 1;
    }
    else if (value1 == 0x510 && value2 == 0x62)
    {
        p_dfe->value = 2;
    }
    else
    {
        p_dfe->value = 0;
    }
    
    return CTC_E_NONE;
}


STATIC int32
_ctc_asw_datapath_serdes_reset(uint8 lchip, uint8 serdes_id)
{
    int32 ret = CTC_E_NONE;

    ret = _ctc_chip_serdes_write(lchip, serdes_id, CTC_ASW_SERDES_ADDRESS(serdes_id, 0x100), 0x800);
    ret = ret?ret:_ctc_chip_serdes_write(lchip, serdes_id, CTC_ASW_SERDES_ADDRESS(serdes_id, 0x102), 0xb040);
    ret = ret?ret:_ctc_chip_serdes_write(lchip, serdes_id, CTC_ASW_SERDES_ADDRESS(serdes_id, 0x102), 0x3040);

    return ret;
}

STATIC int32
_ctc_asw_datapath_release_pcs(uint8 lchip, uint8 serdes_id, uint32 value)
{
    uint32 cmd = 0;
    ds_t ds;
    int32 ret = CTC_E_NONE;

    value = value?0:1;
    cmd = DRV_IOR(ResetCtlNet_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip,0,cmd,&ds);

    if (CTC_CHIP_SERDES_SGMII_MODE == datapath_master[lchip].serdes_info[serdes_id].mode)
    {
        SetResetCtlNet(V, cfgResetSgmii0_f+serdes_id*(ResetCtlNet_cfgResetSgmii1_f-ResetCtlNet_cfgResetSgmii0_f), &ds, value);
        SetResetCtlNet(V, cfgResetSgmii0Reg_f+serdes_id*(ResetCtlNet_cfgResetSgmii1Reg_f-ResetCtlNet_cfgResetSgmii0Reg_f), &ds, value);
    }
    else if (CTC_CHIP_SERDES_QSGMII_MODE == datapath_master[lchip].serdes_info[serdes_id].mode)
    {
        SetResetCtlNet(V, cfgResetQsgmii0_f+(serdes_id-4)*(ResetCtlNet_cfgResetQsgmii1_f-ResetCtlNet_cfgResetQsgmii0_f), &ds, value);
        SetResetCtlNet(V, cfgResetQsgmii0Reg_f+(serdes_id-4)*(ResetCtlNet_cfgResetQsgmii1Reg_f-ResetCtlNet_cfgResetQsgmii0Reg_f), &ds, value);
    }
    else if (CTC_CHIP_SERDES_100BASEFX_MODE == datapath_master[lchip].serdes_info[serdes_id].mode)
    {
        SetResetCtlNet(V, cfgResetFxmii0_f+(serdes_id)*(ResetCtlNet_cfgResetFxmii1_f-ResetCtlNet_cfgResetFxmii0_f), &ds, value);
        SetResetCtlNet(V, cfgResetFxmii0Reg_f+(serdes_id)*(ResetCtlNet_cfgResetFxmii1Reg_f-ResetCtlNet_cfgResetFxmii0Reg_f), &ds, value);
    }
    cmd = DRV_IOW(ResetCtlNet_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    return ret;
}

STATIC int32
_ctc_asw_datapath_release_auto_neg(uint8 lchip, uint8 serdes_id)
{
    uint32 cmd = 0;
    ds_t ds;
    uint8 index = 0;
    int32 ret = CTC_E_NONE;

    if (CTC_CHIP_SERDES_SGMII_MODE == datapath_master[lchip].serdes_info[serdes_id].mode)
    {
        cmd = DRV_IOR(SgmiiPcsRefPulseCfg_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip,serdes_id,cmd,&ds);
        SetSgmiiPcsRefPulseCfg(V, cfgResetDivLinkPulse_f, &ds, 0);
        cmd = DRV_IOW(SgmiiPcsRefPulseCfg_t, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip,serdes_id,cmd,&ds);

        cmd = DRV_IOR(SgmiiPcsCfg_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, serdes_id, cmd, &ds);
		SetSgmiiPcsCfg(V, anEnable_f, &ds, 1);
        SetSgmiiPcsCfg(V, ignoreLinkFailure_f, &ds, 1);
        SetSgmiiPcsCfg(V, ignoreAnegErr_f, &ds, 1);
        SetSgmiiPcsCfg(V, unidirectionEn_f, &ds, 0);
        cmd = DRV_IOW(SgmiiPcsCfg_t, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip, serdes_id, cmd, &ds);
    }
    else if (CTC_CHIP_SERDES_100BASEFX_MODE == datapath_master[lchip].serdes_info[serdes_id].mode)
    {
        cmd = DRV_IOR(FxPcsRefPulseCfg_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip,serdes_id,cmd,&ds);
        SetFxPcsRefPulseCfg(V, cfgResetDivLinkPulse_f, &ds, 0);
        cmd = DRV_IOW(FxPcsRefPulseCfg_t, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip,serdes_id,cmd,&ds);
    }
    else if (CTC_CHIP_SERDES_QSGMII_MODE == datapath_master[lchip].serdes_info[serdes_id].mode)
    {
        cmd = DRV_IOR(QsgmiiPcsRefPulseCfg_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip,serdes_id-4,cmd,&ds);
        SetQsgmiiPcsRefPulseCfg(V, cfgResetDivLinkPulse_f, &ds, 0);
        cmd = DRV_IOW(QsgmiiPcsRefPulseCfg_t, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip,serdes_id-4,cmd,&ds);

        cmd = DRV_IOR(QsgmiiPcsSoftRst_t, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip, serdes_id-4, cmd, &ds);
        SetQsgmiiPcsSoftRst(V, qsgmiiPmaRxSoftRst_f, &ds, 0);
        SetQsgmiiPcsSoftRst(V, qsgmiiPcsTxSoftRst_f, &ds, 0);
        cmd = DRV_IOW(QsgmiiPcsSoftRst_t, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip, serdes_id-4, cmd, &ds);

        for (index=0; index<4; index++)
        {
            cmd = DRV_IOR(QsgmiiPcsAneg0Cfg_t+index, DRV_ENTRY_FLAG);
            ret = DRV_IOCTL(lchip, serdes_id-4, cmd, &ds);
            SetQsgmiiPcsAneg0Cfg(V, anEnable0_f, &ds, 1);
            SetQsgmiiPcsAneg0Cfg(V, ignoreLinkFailure0_f, &ds, 1);
            SetQsgmiiPcsAneg0Cfg(V, ignoreAnegErr0_f, &ds, 1);
            cmd = DRV_IOW(QsgmiiPcsAneg0Cfg_t+index, DRV_ENTRY_FLAG);
            ret = ret?ret:DRV_IOCTL(lchip, serdes_id-4, cmd, &ds);
        }
    }

    return ret;
}
STATIC int32
_ctc_asw_datapath_build_serdes_info(uint8 lchip, uint16 serdes_id, uint8 serdes_mode)
{
    int32 ret = CTC_E_NONE;
    uint16 lport = 0;
    uint8 index = 0;

    if (CTC_CHIP_SERDES_SGMII_MODE == datapath_master[lchip].serdes_info[serdes_id].mode
       || CTC_CHIP_SERDES_100BASEFX_MODE == datapath_master[lchip].serdes_info[serdes_id].mode)
    {
        if (CTC_ASW_SERDES_IS_SOUTH_HSS(serdes_id))
        {
            /*sourth hss lport*/
            lport = CTC_ASW_MAX_PHY_PORT-1-serdes_id;
        }
        else
        {
            /*north hss lport*/
            lport = CTC_ASW_MAX_PHY_PORT-((serdes_id-2)<<2);
        }
        datapath_master[lchip].port_attr[lport].port_type = CTC_ASW_DATAPATH_RSV_PORT;
    }
    else if (CTC_CHIP_SERDES_QSGMII_MODE == datapath_master[lchip].serdes_info[serdes_id].mode)
    {
        lport = CTC_ASW_MAX_PHY_PORT-((serdes_id-2)<<2);
        for (index=0; index<4; index++)
        {
            datapath_master[lchip].port_attr[lport+index].port_type = CTC_ASW_DATAPATH_RSV_PORT;
        }
    }
    else if (CTC_CHIP_SERDES_PHY_MODE == datapath_master[lchip].serdes_info[serdes_id].mode)
    {
        lport = serdes_id-CTC_ASW_MAX_NORMAL_SERDES_NUM;
        datapath_master[lchip].port_attr[lport].port_type = CTC_ASW_DATAPATH_RSV_PORT;
    }

    if (CTC_CHIP_SERDES_PHY_MODE == serdes_mode)
    {
        lport = serdes_id-CTC_ASW_MAX_NORMAL_SERDES_NUM;
        datapath_master[lchip].port_attr[lport].port_type = CTC_ASW_DATAPATH_NETWORK_PORT;
        datapath_master[lchip].port_attr[lport].mac_id = lport;
        datapath_master[lchip].port_attr[lport].serdes_id = serdes_id;
        datapath_master[lchip].port_attr[lport].pcs_mode = CTC_CHIP_SERDES_PHY_MODE;
        datapath_master[lchip].port_attr[lport].speed_mode = CTC_PORT_SPEED_1G;
        datapath_master[lchip].serdes_info[serdes_id].mode = CTC_CHIP_SERDES_PHY_MODE;
        datapath_master[lchip].serdes_info[serdes_id].lport = lport;
        datapath_master[lchip].serdes_info[serdes_id].port_num = 1;
    }
    else if ((CTC_CHIP_SERDES_NONE_MODE != serdes_mode)&& (serdes_id < CTC_ASW_MAX_NORMAL_SERDES_NUM))
    {
        if (CTC_CHIP_SERDES_QSGMII_MODE != serdes_mode)
        {
            if (CTC_ASW_SERDES_IS_SOUTH_HSS(serdes_id))
            {
                /*sourth hss lport*/
                lport = CTC_ASW_MAX_PHY_PORT-1-serdes_id;
            }
            else
            {
                /*north hss lport*/
                lport = CTC_ASW_MAX_PHY_PORT-((serdes_id-2)<<2);
            }
            datapath_master[lchip].port_attr[lport].port_type = CTC_ASW_DATAPATH_NETWORK_PORT;
            datapath_master[lchip].port_attr[lport].mac_id = lport;
            datapath_master[lchip].port_attr[lport].serdes_id = serdes_id;
            datapath_master[lchip].port_attr[lport].pcs_mode = serdes_mode;
            datapath_master[lchip].port_attr[lport].speed_mode = (serdes_mode == CTC_CHIP_SERDES_SGMII_MODE)?CTC_PORT_SPEED_1G:CTC_PORT_SPEED_100M;
            datapath_master[lchip].serdes_info[serdes_id].lport = lport;
            datapath_master[lchip].serdes_info[serdes_id].port_num = 1;
        }
        else
        {
            lport = CTC_ASW_MAX_PHY_PORT-((serdes_id-2)<<2);
            for (index=0; index<4; index++)
            {
                datapath_master[lchip].port_attr[lport+index].port_type = CTC_ASW_DATAPATH_NETWORK_PORT;
                datapath_master[lchip].port_attr[lport+index].mac_id = lport+index;
                datapath_master[lchip].port_attr[lport+index].serdes_id = serdes_id;
                datapath_master[lchip].port_attr[lport+index].pcs_mode = serdes_mode;
                datapath_master[lchip].port_attr[lport+index].speed_mode = CTC_PORT_SPEED_1G;
            }
            datapath_master[lchip].serdes_info[serdes_id].lport = lport;
            datapath_master[lchip].serdes_info[serdes_id].port_num = 4;
        }
        datapath_master[lchip].serdes_info[serdes_id].mode = serdes_mode;
    }
    else if (CTC_CHIP_SERDES_NONE_MODE == serdes_mode)
    {
        datapath_master[lchip].serdes_info[serdes_id].mode = serdes_mode;
    }

    return ret;
}

#define ______DATAPATH_INTERNAL_API______
int32
_ctc_chip_serdes_read(uint8 lchip, uint8 serdes_id, uint32 address, uint16* p_value16)
{
    uint8 serdes_mdio_address[]={0x8,0x8,0x9,0x9,0xa,0xa,0xb,0xb};
    ctc_chip_mdio_para_t mdio_para;
    int32 ret = CTC_E_NONE;

    sal_memset(&mdio_para, 0, sizeof(mdio_para));
    mdio_para.bus = 0;
    mdio_para.phy_addr = serdes_mdio_address[serdes_id];
    mdio_para.reg = 0x1e;
    mdio_para.value = address;
    CTC_MDIO_LOCK(lchip);
    ret = _ctc_asw_chip_mdio_write(lchip, CTC_CHIP_MDIO_GE, &mdio_para);
    mdio_para.reg = 0x1f;
    ret = ret?ret:_ctc_asw_chip_mdio_read(lchip, CTC_CHIP_MDIO_GE, &mdio_para);
    CTC_MDIO_UNLOCK(lchip);
    *p_value16 = mdio_para.value;
    return CTC_E_NONE;
}

int32
_ctc_chip_serdes_write(uint8 lchip, uint8 serdes_id, uint32 address, uint16 value16)
{
    uint8 serdes_mdio_address[]={0x8,0x8,0x9,0x9,0xa,0xa,0xb,0xb};
    ctc_chip_mdio_para_t mdio_para;
    uint32 devid = 0;
    uint32 cmd = 0;
    int32 ret = CTC_E_NONE;

    cmd = DRV_IOR(DeviceId_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &devid));
    sal_memset(&mdio_para, 0, sizeof(mdio_para));
    mdio_para.bus = 0;
    mdio_para.phy_addr = serdes_mdio_address[serdes_id];
    mdio_para.reg = 0x1e;
    mdio_para.value = (0 == ((devid>>16) & 0xF))?(address&0x0FF):address;  /*verison 0, must use broast write*/
    CTC_MDIO_LOCK(lchip);
    ret = _ctc_asw_chip_mdio_write(lchip, CTC_CHIP_MDIO_GE, &mdio_para);
    mdio_para.reg = 0x1f;
    mdio_para.value = value16;
    ret = ret?ret:_ctc_asw_chip_mdio_write(lchip, CTC_CHIP_MDIO_GE, &mdio_para);
    CTC_MDIO_UNLOCK(lchip);
    return ret;
}

int32
_ctc_asw_datapath_get_link_up(uint8 lchip, uint32 gport, uint32* p_value)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    ds_t ds;
    uint8 serdes_type = 0;
    uint8 serdes_act_id = 0;
    uint8 mac_id = 0;
    uint8 link_status = 0;
    uint8 fx_rx_lock = 0;
    uint8 unidir_en = 0;

    serdes_type = datapath_master[lchip].port_attr[gport].pcs_mode;
    serdes_act_id = datapath_master[lchip].port_attr[gport].serdes_id;
    mac_id = datapath_master[lchip].port_attr[gport].mac_id;
    if (serdes_type == CTC_CHIP_SERDES_PHY_MODE)
    {
		*p_value = 1;
    }
    else if (serdes_type == CTC_CHIP_SERDES_QSGMII_MODE)
    {
        cmd = DRV_IOR(QsgmiiPcsStatus0_t+mac_id%4, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, serdes_act_id-4, cmd, &ds);
        *p_value = GetQsgmiiPcsStatus0(V, anLinkStatus0_f, &ds);
    }
    else if (serdes_type == CTC_CHIP_SERDES_SGMII_MODE)
    {
        cmd = DRV_IOR(SgmiiPcsCfg_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
        unidir_en = GetSgmiiPcsCfg(V, unidirectionEn_f, &ds);
        cmd = DRV_IOR(SgmiiPcsSgmiiStatus_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
        if (unidir_en)
        {
            *p_value = GetSgmiiPcsSgmiiStatus(V, sgmiiSyncStatus_f, &ds);
        }
        else
        {
            *p_value = GetSgmiiPcsSgmiiStatus(V, anLinkStatus_f, &ds);
        }
    }
    else if(serdes_type == CTC_CHIP_SERDES_100BASEFX_MODE)
    {
        cmd = DRV_IOR(FxPcsStatus_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
        link_status = GetFxPcsStatus(V, dbgFxLinkStatus_f, &ds);
        fx_rx_lock = GetFxPcsStatus(V, dbgFxRxBitLock_f, &ds);
        if(link_status && fx_rx_lock)
        {
            *p_value = 1;
        }
        else if(1 == link_status && 0 == fx_rx_lock)
        {
            *p_value = 0;
            cmd = DRV_IOR(FxPcsSoftRst_t, DRV_ENTRY_FLAG);
            ret = DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
            SetFxPcsSoftRst(V, fxPcsRxSoftRst_f, &ds, 1);
            SetFxPcsSoftRst(V, fxPcsTxSoftRst_f, &ds, 1);
            cmd = DRV_IOW(FxPcsSoftRst_t, DRV_ENTRY_FLAG);
            ret = ret?ret:DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
            sal_task_sleep(10);
            cmd = DRV_IOR(FxPcsSoftRst_t, DRV_ENTRY_FLAG);
            ret = ret?ret:DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
            SetFxPcsSoftRst(V, fxPcsRxSoftRst_f, &ds, 0);
            SetFxPcsSoftRst(V, fxPcsTxSoftRst_f, &ds, 0);
            cmd = DRV_IOW(FxPcsSoftRst_t, DRV_ENTRY_FLAG);
            ret = ret?ret:DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
        }
        else
        {
            *p_value = 0;
        }
    }
    else
    {
        ret = CTC_E_INVALID_PARAM;
    }

    return ret;
}

int32
_ctc_asw_datapath_set_pcs_en(uint8 lchip, uint32 gport, uint32 enable)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    ds_t ds;
    uint8 serdes_type = 0;
    uint8 serdes_act_id = 0;
    uint8 mac_id = 0;
    uint32 value = enable?0:1;
    if (gport == CTC_ASW_CPU_PORT_1)
    {
        return CTC_E_NONE;
    }
    serdes_type = datapath_master[lchip].port_attr[gport].pcs_mode;
    serdes_act_id = datapath_master[lchip].port_attr[gport].serdes_id;
    mac_id = datapath_master[lchip].port_attr[gport].mac_id;
    if (serdes_type == CTC_CHIP_SERDES_PHY_MODE)
    {
		/* nothing to do */
    }
    else if (serdes_type == CTC_CHIP_SERDES_QSGMII_MODE)
    {
        cmd = DRV_IOR(QsgmiiPcsSoftRst_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, serdes_act_id-4, cmd, &ds);

		SetQsgmiiPcsSoftRst(V, qsgmiiPcsRxSoftRst0_f+(mac_id%4)*(QsgmiiPcsSoftRst_qsgmiiPcsRxSoftRst1_f-QsgmiiPcsSoftRst_qsgmiiPcsRxSoftRst0_f), &ds, value);
		SetQsgmiiPcsSoftRst(V, qsgmiiPcsTxSoftRst0_f+(mac_id%4)*(QsgmiiPcsSoftRst_qsgmiiPcsTxSoftRst1_f-QsgmiiPcsSoftRst_qsgmiiPcsTxSoftRst0_f), &ds, value);
#if 0
		SetQsgmiiPcsSoftRst(V, qsgmiiPmaRxSoftRst_f, &ds, value);
		SetQsgmiiPcsSoftRst(V, qsgmiiPcsTxSoftRst_f, &ds, value);
#endif
        cmd = DRV_IOW(QsgmiiPcsSoftRst_t, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip, serdes_act_id-4, cmd, &ds);
    }
    else if (serdes_type == CTC_CHIP_SERDES_SGMII_MODE)
    {
        cmd = DRV_IOR(SgmiiPcsSoftRst_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
		SetSgmiiPcsSoftRst(V, sgmiiPcsRxSoftRst_f, &ds, value);
		SetSgmiiPcsSoftRst(V, sgmiiPcsTxSoftRst_f, &ds, value);
        cmd = DRV_IOW(SgmiiPcsSoftRst_t, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
        if(enable == 0)
        {
            _ctc_chip_serdes_write(lchip, serdes_act_id, CTC_ASW_SERDES_ADDRESS(serdes_act_id, 0x105), 0xc100);
            sal_task_sleep(100);
            _ctc_chip_serdes_write(lchip, serdes_act_id, CTC_ASW_SERDES_ADDRESS(serdes_act_id, 0x105), 0x0000);
        }
    }
    else if (CTC_CHIP_SERDES_100BASEFX_MODE == serdes_type)
    {
        cmd = DRV_IOR(FxPcsSoftRst_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
		SetFxPcsSoftRst(V, fxPcsRxSoftRst_f, &ds, value);
		SetFxPcsSoftRst(V, fxPcsTxSoftRst_f, &ds, value);
        cmd = DRV_IOW(FxPcsSoftRst_t, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
        cmd = DRV_IOR(FxPcsCfg_t, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
		SetFxPcsCfg(V, cfgFxLinkEnable_f, &ds, 1);
        SetFxPcsCfg(V, cfgFxRxEdgeDistVec_f, &ds, 0x3e0);
        cmd = DRV_IOW(FxPcsCfg_t, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
    }
    else
    {
        ret = CTC_E_INVALID_PARAM;
    }

    return ret;
}

int32
_ctc_asw_datapath_get_pcs_en(uint8 lchip, uint32 gport, uint32* p_enable)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    ds_t ds;
    uint8 serdes_type = 0;
    uint8 serdes_act_id = 0;
    uint32 value = 0;

    *p_enable = 0;
    if (gport == CTC_ASW_CPU_PORT_1)
    {
        *p_enable = 1;
        return CTC_E_NONE;
    }
    serdes_type = datapath_master[lchip].port_attr[gport].pcs_mode;
    serdes_act_id = datapath_master[lchip].port_attr[gport].serdes_id;
    if (serdes_type == CTC_CHIP_SERDES_PHY_MODE)
    {
		/* nothing to do */
    }
    else if (serdes_type == CTC_CHIP_SERDES_QSGMII_MODE)
    {
        cmd = DRV_IOR(QsgmiiPcsSoftRst_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, serdes_act_id-4, cmd, &ds);
		value = GetQsgmiiPcsSoftRst(V, qsgmiiPcsRxSoftRst0_f+(gport%4)*(QsgmiiPcsSoftRst_qsgmiiPcsRxSoftRst1_f-QsgmiiPcsSoftRst_qsgmiiPcsRxSoftRst0_f), &ds);
    }
    else if (serdes_type == CTC_CHIP_SERDES_SGMII_MODE)
    {
        cmd = DRV_IOR(SgmiiPcsSoftRst_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
		value = GetSgmiiPcsSoftRst(V, sgmiiPcsRxSoftRst_f, &ds);
    }
    else if (CTC_CHIP_SERDES_100BASEFX_MODE == serdes_type)
    {
        cmd = DRV_IOR(FxPcsSoftRst_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
		value = GetFxPcsSoftRst(V, fxPcsRxSoftRst_f, &ds);
    } 
    else
    {
        ret = CTC_E_INVALID_PARAM;
    }
    *p_enable = value?0:1;

    return ret;
}

int32
_ctc_asw_datapath_set_pcs_type(uint8 lchip, uint32 gport, ctc_chip_serdes_mode_t serdes_mode)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    QsgmiiMode_m qsgmii_mode;
    SgmiiMode_m sgmii_mode;
    FxmiiMode_m fxmii_mode;
    uint8 serdes_act_id = 0;
    uint32 qsgmii_val = 0;
    uint32 sgmii_val = 0;
    uint32 fxmii_val = 0;
    serdes_act_id = datapath_master[lchip].port_attr[gport].serdes_id;
    if (serdes_mode == CTC_CHIP_SERDES_PHY_MODE || serdes_mode == CTC_CHIP_SERDES_RGMII_MODE)
    {
		return CTC_E_NONE;
    }
    /*check serdes mode*/
    if(((CTC_CHIP_SERDES_PHY_MODE != serdes_mode) && CTC_ASW_SERDES_IS_PHY(serdes_act_id)) 
        || ((CTC_CHIP_SERDES_100BASEFX_MODE != serdes_mode && CTC_CHIP_SERDES_SGMII_MODE != serdes_mode ) && CTC_ASW_SERDES_IS_SOUTH_HSS(serdes_act_id))
        || ((CTC_CHIP_SERDES_QSGMII_MODE != serdes_mode && CTC_CHIP_SERDES_100BASEFX_MODE != serdes_mode && CTC_CHIP_SERDES_QSGMII_MODE != serdes_mode ) && CTC_ASW_SERDES_IS_NORTH_HSS(serdes_act_id))
        || (CTC_CHIP_SERDES_RGMII_MODE != serdes_mode && CTC_ASW_SERDES_IS_CPU_MAC(serdes_act_id)))
    {
        return CTC_E_INVALID_PARAM;
    }

    ret = _ctc_asw_datapath_release_pcs(lchip, serdes_act_id, 0);
    cmd = DRV_IOR(QsgmiiMode_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&qsgmii_mode);
    qsgmii_val = GetQsgmiiMode(V, modeQsgmii_f, &qsgmii_mode);
    cmd = DRV_IOR(SgmiiMode_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&sgmii_mode);
    sgmii_val = GetSgmiiMode(V, modeSgmii_f, &sgmii_mode);
    cmd = DRV_IOR(FxmiiMode_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&fxmii_mode);
    fxmii_val = GetFxmiiMode(V, modeFxmii_f, &fxmii_mode);

    if (serdes_mode == CTC_CHIP_SERDES_QSGMII_MODE)
    {
        CTC_BIT_SET(qsgmii_val, serdes_act_id-4);
        CTC_BIT_UNSET(sgmii_val, serdes_act_id);
        CTC_BIT_UNSET(fxmii_val, serdes_act_id);
    }
    else if (serdes_mode == CTC_CHIP_SERDES_SGMII_MODE)
    {
        CTC_BIT_SET(sgmii_val, serdes_act_id);
        CTC_BIT_UNSET(fxmii_val, serdes_act_id);
        if (serdes_act_id > 4)
        {
            CTC_BIT_UNSET(qsgmii_val, serdes_act_id-4);
        }
    }
    else if (serdes_mode == CTC_CHIP_SERDES_100BASEFX_MODE)
    {
        CTC_BIT_SET(fxmii_val, serdes_act_id);
        CTC_BIT_UNSET(sgmii_val, serdes_act_id);
        if (serdes_act_id > 4)
        {
            CTC_BIT_UNSET(qsgmii_val, serdes_act_id-4);
        }
    }
    else
    {
        ret = CTC_E_INVALID_PARAM;
    }
    SetQsgmiiMode(V, modeQsgmii_f, &qsgmii_mode, qsgmii_val);
    SetSgmiiMode(V, modeSgmii_f, &sgmii_mode,sgmii_val);
    SetFxmiiMode(V, modeFxmii_f, &fxmii_mode, fxmii_val);
    cmd = DRV_IOW(QsgmiiMode_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&qsgmii_mode);
    cmd = DRV_IOW(SgmiiMode_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&sgmii_mode);
    cmd = DRV_IOW(FxmiiMode_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&fxmii_mode);
    ret = ret?ret:_ctc_asw_datapath_build_serdes_info(lchip, serdes_act_id, serdes_mode);
    ret = ret?ret:_ctc_asw_datapath_release_pcs(lchip, serdes_act_id, 0);
    ret = ret?ret:_ctc_asw_datapath_release_pcs(lchip, serdes_act_id, 1);
    ret = ret?ret:_ctc_asw_datapath_release_auto_neg(lchip, serdes_act_id);
    return ret;
}

int32
_ctc_asw_datapath_get_pcs_type(uint8 lchip, uint32 gport, ctc_chip_serdes_mode_t* p_serdes_mode)
{
    *p_serdes_mode = datapath_master[lchip].port_attr[gport].pcs_mode;

    return CTC_E_NONE;
}

int32
_ctc_asw_datapath_set_auto_neg_mode(uint8 lchip, uint32 gport, ctc_port_auto_neg_mode_t auto_neg_mode)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    ds_t ds;
    uint32 mode_value = 0;
    uint8 serdes_type = 0;
    uint8 serdes_act_id = 0;
    uint8 mac_id = 0;
    serdes_type = datapath_master[lchip].port_attr[gport].pcs_mode;
    serdes_act_id = datapath_master[lchip].port_attr[gport].serdes_id;
    mac_id = datapath_master[lchip].port_attr[gport].mac_id;
    if (CTC_PORT_AUTO_NEG_MODE_1000BASE_X == auto_neg_mode)
    {
		mode_value = 0;
    }
    else if (CTC_PORT_AUTO_NEG_MODE_SGMII_MASTER == auto_neg_mode)
	{
		mode_value = 1;
	}
	else if (CTC_PORT_AUTO_NEG_MODE_SGMII_SLAVER == auto_neg_mode)
	{
		mode_value = 2;
	}
    else
    {
        return CTC_E_INVALID_PARAM;
    }

	if ((CTC_CHIP_SERDES_PHY_MODE == serdes_type)
       || (CTC_CHIP_SERDES_100BASEFX_MODE == serdes_type))
	{
		return CTC_E_NONE;
	}
	else if (CTC_CHIP_SERDES_QSGMII_MODE == serdes_type)
	{
        cmd = DRV_IOR(QsgmiiPcsAneg0Cfg_t+mac_id%4, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, serdes_act_id-4, cmd, &ds);
        SetQsgmiiPcsAneg0Cfg(V, anegMode0_f, &ds, mode_value);
        cmd = DRV_IOW(QsgmiiPcsAneg0Cfg_t+mac_id%4, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip, serdes_act_id-4, cmd, &ds);
	}
	else if (CTC_CHIP_SERDES_SGMII_MODE == serdes_type)
	{
        cmd = DRV_IOR(SgmiiPcsCfg_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
		SetSgmiiPcsCfg(V, anegMode_f, &ds, mode_value);
        cmd = DRV_IOW(SgmiiPcsCfg_t, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
	}
    else
    {
        ret = CTC_E_INVALID_PARAM;
    }

    return ret;
}

int32
_ctc_asw_datapath_get_auto_neg_mode(uint8 lchip, uint32 gport, ctc_port_auto_neg_mode_t* p_auto_neg_mode)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    ds_t ds;
    uint32 mode_value = 0;
    uint8 serdes_type = 0;
    uint8 serdes_act_id = 0;
    uint8 mac_id = 0;
    serdes_type = datapath_master[lchip].port_attr[gport].pcs_mode;
    serdes_act_id = datapath_master[lchip].port_attr[gport].serdes_id;
    mac_id = datapath_master[lchip].port_attr[gport].mac_id;

	if ((CTC_CHIP_SERDES_PHY_MODE == serdes_type)
        || (CTC_CHIP_SERDES_100BASEFX_MODE == serdes_type))
	{
		mode_value = 2;
	}
	else if (CTC_CHIP_SERDES_QSGMII_MODE == serdes_type)
	{
        cmd = DRV_IOR(QsgmiiPcsAneg0Cfg_t+mac_id%4, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, serdes_act_id-4, cmd, &ds);
        mode_value = GetQsgmiiPcsAneg0Cfg(V, anegMode0_f, &ds);
	}
	else if (CTC_CHIP_SERDES_SGMII_MODE == serdes_type)
	{
        cmd = DRV_IOR(SgmiiPcsCfg_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
		mode_value = GetSgmiiPcsCfg(V, anegMode_f, &ds);
	}
    else
    {
        ret = CTC_E_INVALID_PARAM;
    }

    if (0 == mode_value)
    {
		*p_auto_neg_mode = CTC_PORT_AUTO_NEG_MODE_1000BASE_X;
    }
    else if (1 == mode_value)
	{
        *p_auto_neg_mode = CTC_PORT_AUTO_NEG_MODE_SGMII_MASTER;
	}
	else if (2 == mode_value)
	{
        *p_auto_neg_mode = CTC_PORT_AUTO_NEG_MODE_SGMII_SLAVER;
	}
    return ret;
}

int32
_ctc_asw_datapath_set_auto_neg_enable(uint8 lchip, uint32 gport, uint32 enable)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    ds_t ds;
    uint8 serdes_type = 0;
    uint8 serdes_act_id = 0;
    uint8 mac_id = 0;
    serdes_type = datapath_master[lchip].port_attr[gport].pcs_mode;
    serdes_act_id = datapath_master[lchip].port_attr[gport].serdes_id;
    mac_id = datapath_master[lchip].port_attr[gport].mac_id;

	if ((CTC_CHIP_SERDES_PHY_MODE == serdes_type)
        || (CTC_CHIP_SERDES_100BASEFX_MODE == serdes_type))
	{
		return CTC_E_NONE;
	}
	else if (CTC_CHIP_SERDES_QSGMII_MODE == serdes_type)
	{
        cmd = DRV_IOR(QsgmiiPcsAneg0Cfg_t+mac_id%4, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, serdes_act_id-4, cmd, &ds);
        SetQsgmiiPcsAneg0Cfg(V, anEnable0_f, &ds, enable?1:0);
        SetQsgmiiPcsAneg0Cfg(V, ignoreLinkFailure0_f, &ds, enable?1:0);
        SetQsgmiiPcsAneg0Cfg(V, ignoreAnegErr0_f, &ds, enable?1:0);
        cmd = DRV_IOW(QsgmiiPcsAneg0Cfg_t+mac_id%4, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip, serdes_act_id-4, cmd, &ds);
	}
	else if (CTC_CHIP_SERDES_SGMII_MODE == serdes_type)
	{
        cmd = DRV_IOR(SgmiiPcsCfg_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
		SetSgmiiPcsCfg(V, anEnable_f, &ds, enable?1:0);
        SetSgmiiPcsCfg(V, ignoreLinkFailure_f, &ds, enable?1:0);
        SetSgmiiPcsCfg(V, ignoreAnegErr_f, &ds, enable?1:0);
        SetSgmiiPcsCfg(V, unidirectionEn_f, &ds, enable?0:1);
        cmd = DRV_IOW(SgmiiPcsCfg_t, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
	}
    else
    {
        ret = CTC_E_INVALID_PARAM;
    }

    return ret;
}

int32
_ctc_asw_datapath_get_auto_neg_enable(uint8 lchip, uint32 gport, uint32* p_enable)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    ds_t ds;
    uint8 serdes_type = 0;
    uint8 serdes_act_id = 0;
    uint8 mac_id = 0;
    serdes_type = datapath_master[lchip].port_attr[gport].pcs_mode;
    serdes_act_id = datapath_master[lchip].port_attr[gport].serdes_id;
    mac_id = datapath_master[lchip].port_attr[gport].mac_id;

	if (CTC_CHIP_SERDES_PHY_MODE == serdes_type)
	{
        *p_enable = 1;
		return CTC_E_NONE;
	}
    else if (CTC_CHIP_SERDES_100BASEFX_MODE == serdes_type)
    {
        *p_enable = 0;
        return CTC_E_NONE;
    }
	else if (CTC_CHIP_SERDES_QSGMII_MODE == serdes_type)
	{
        cmd = DRV_IOR(QsgmiiPcsAneg0Cfg_t+mac_id%4, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, serdes_act_id-4, cmd, &ds);
        *p_enable = GetQsgmiiPcsAneg0Cfg(V, anEnable0_f, &ds);
	}
	else if (CTC_CHIP_SERDES_SGMII_MODE == serdes_type)
	{
        cmd = DRV_IOR(SgmiiPcsCfg_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
		*p_enable = GetSgmiiPcsCfg(V, anEnable_f, &ds);
	}
    else
    {
        ret = CTC_E_INVALID_PARAM;
    }

    return ret;
}

int32
_ctc_asw_datapath_set_pcs_link_isr_en(uint8 lchip, uint32 gport, uint32 enable)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    ds_t ds;
    uint8 serdes_type = 0;
    uint8 serdes_act_id = 0;
    uint32 tbl_index = 0;
    serdes_type = datapath_master[lchip].port_attr[gport].pcs_mode;
    serdes_act_id = datapath_master[lchip].port_attr[gport].serdes_id;

    sal_memset(&ds, 0, sizeof(ds));

    if (enable)
    {
        tbl_index = 3;
    }
    else
    {
        tbl_index = 2;
    }
	if (CTC_CHIP_SERDES_PHY_MODE == serdes_type)
	{
		return CTC_E_NONE;
	}
    else if (CTC_CHIP_SERDES_100BASEFX_MODE == serdes_type)
    {
        SetSupPcsFuncIntr(V, fx0LinkUp_f+(serdes_act_id)*(SupPcsFuncIntr_fx1LinkUp_f-SupPcsFuncIntr_fx0LinkUp_f), &ds, 1);
        SetSupPcsFuncIntr(V, fx0LinkDown_f+(serdes_act_id)*(SupPcsFuncIntr_fx1LinkDown_f-SupPcsFuncIntr_fx0LinkDown_f), &ds, 1);
    }
	else if (CTC_CHIP_SERDES_QSGMII_MODE == serdes_type)
	{
        SetSupPcsFuncIntr(V, qsgmii1LinkUp_f+(gport-8)*(SupPcsFuncIntr_qsgmii1LinkUp_f-SupPcsFuncIntr_qsgmii0LinkUp_f), &ds, 1);
        SetSupPcsFuncIntr(V, qsgmii1LinkDown_f+(gport-8)*(SupPcsFuncIntr_qsgmii1LinkDown_f-SupPcsFuncIntr_qsgmii0LinkDown_f), &ds, 1);
	}
	else if (CTC_CHIP_SERDES_SGMII_MODE == serdes_type)
	{
        SetSupPcsFuncIntr(V, sgmii0LinkUp_f+(serdes_act_id)*(SupPcsFuncIntr_sgmii1LinkUp_f-SupPcsFuncIntr_sgmii0LinkUp_f), &ds, 1);
        SetSupPcsFuncIntr(V, sgmii0LinkDown_f+(serdes_act_id)*(SupPcsFuncIntr_sgmii1LinkDown_f-SupPcsFuncIntr_sgmii0LinkDown_f), &ds, 1);
	}
    else
    {
        ret = CTC_E_INVALID_PARAM;
    }

    cmd = DRV_IOW(SupPcsFuncIntr_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip, tbl_index, cmd, &ds);
    return ret;
}

int32
_ctc_asw_datapath_get_pcs_link_isr_en(uint8 lchip, uint32 gport, uint32* p_enable)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    ds_t ds;
    uint8 serdes_type = 0;
    uint8 serdes_act_id = 0;

    serdes_type = datapath_master[lchip].port_attr[gport].pcs_mode;
    serdes_act_id = datapath_master[lchip].port_attr[gport].serdes_id;

    cmd = DRV_IOR(SupPcsFuncIntr_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, 2, cmd, &ds);
	if (CTC_CHIP_SERDES_PHY_MODE == serdes_type)
	{
        *p_enable = FALSE;
		return CTC_E_NONE;
	}
    else if (CTC_CHIP_SERDES_100BASEFX_MODE == serdes_type)
    {
        *p_enable = GetSupPcsFuncIntr(V, fx0LinkUp_f+(serdes_act_id)*(SupPcsFuncIntr_fx1LinkUp_f-SupPcsFuncIntr_fx0LinkUp_f), &ds)?0:1;
    }
	else if (CTC_CHIP_SERDES_QSGMII_MODE == serdes_type)
	{
        *p_enable = GetSupPcsFuncIntr(V, qsgmii1LinkUp_f+(gport-8)*(SupPcsFuncIntr_qsgmii1LinkUp_f-SupPcsFuncIntr_qsgmii0LinkUp_f), &ds)?0:1;
	}
	else if (CTC_CHIP_SERDES_SGMII_MODE == serdes_type)
	{
        *p_enable = GetSupPcsFuncIntr(V, sgmii0LinkUp_f+(serdes_act_id)*(SupPcsFuncIntr_sgmii1LinkUp_f-SupPcsFuncIntr_sgmii0LinkUp_f), &ds)?0:1;
	}
    else
    {
        ret = CTC_E_INVALID_PARAM;
    }

    return ret;
}

int32
_ctc_asw_datapath_set_unidir_en(uint8 lchip, uint32 gport, uint32 enable)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    ds_t ds;
    uint8 serdes_type = 0;
    uint8 serdes_act_id = 0;
    uint8 mac_id = 0;
    serdes_type = datapath_master[lchip].port_attr[gport].pcs_mode;
    serdes_act_id = datapath_master[lchip].port_attr[gport].serdes_id;
    mac_id = datapath_master[lchip].port_attr[gport].mac_id;

	if ((CTC_CHIP_SERDES_PHY_MODE == serdes_type)
        || (CTC_CHIP_SERDES_100BASEFX_MODE == serdes_type))
	{
		return CTC_E_NONE;
	}
	else if (CTC_CHIP_SERDES_QSGMII_MODE == serdes_type)
	{
        cmd = DRV_IOR(QsgmiiPcsCfg_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, serdes_act_id-4, cmd, &ds);
        SetQsgmiiPcsCfg(V, unidirectionEn0_f+(mac_id%4)*(QsgmiiPcsCfg_unidirectionEn1_f-QsgmiiPcsCfg_unidirectionEn0_f), &ds, enable?1:0);
        cmd = DRV_IOW(QsgmiiPcsAneg0Cfg_t, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip, serdes_act_id-4, cmd, &ds);
	}
	else if (CTC_CHIP_SERDES_SGMII_MODE == serdes_type)
	{
        cmd = DRV_IOR(SgmiiPcsCfg_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
		SetSgmiiPcsCfg(V, unidirectionEn_f, &ds, enable?1:0);
        cmd = DRV_IOW(SgmiiPcsCfg_t, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
	}
    else
    {
        ret = CTC_E_INVALID_PARAM;
    }

    return ret;
}

int32
_ctc_asw_datapath_get_unidir_en(uint8 lchip, uint32 gport, uint32* p_enable)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    ds_t ds;
    uint8 serdes_type = 0;
    uint8 serdes_act_id = 0;
    uint8 mac_id = 0;
    serdes_type = datapath_master[lchip].port_attr[gport].pcs_mode;
    serdes_act_id = datapath_master[lchip].port_attr[gport].serdes_id;
    mac_id = datapath_master[lchip].port_attr[gport].mac_id;

	if ((CTC_CHIP_SERDES_PHY_MODE == serdes_type)
       || (CTC_CHIP_SERDES_100BASEFX_MODE == serdes_type))
	{
		return CTC_E_NONE;
	}
	else if (CTC_CHIP_SERDES_QSGMII_MODE == serdes_type)
	{
        cmd = DRV_IOR(QsgmiiPcsCfg_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, serdes_act_id-4, cmd, &ds);
        *p_enable = GetQsgmiiPcsCfg(V, unidirectionEn0_f+(mac_id%4)*(QsgmiiPcsCfg_unidirectionEn1_f-QsgmiiPcsCfg_unidirectionEn0_f), &ds);
	}
	else if (CTC_CHIP_SERDES_SGMII_MODE == serdes_type)
	{
        cmd = DRV_IOR(SgmiiPcsCfg_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, serdes_act_id, cmd, &ds);
		*p_enable = GetSgmiiPcsCfg(V, unidirectionEn_f, &ds);
	}
    else
    {
        ret = CTC_E_INVALID_PARAM;
    }

    return ret;
}


int32
_ctc_asw_datapath_get_serdes_id(uint8 lchip, uint32 gport, uint8* p_serdes_id)
{
    if (CTC_CHIP_SERDES_NONE_MODE !=  datapath_master[lchip].port_attr[gport].pcs_mode)
    {
        *p_serdes_id = datapath_master[lchip].port_attr[gport].serdes_id;
    }
    else
    {
        return CTC_E_NOT_INIT;
    }
    
    return CTC_E_NONE;
}

int32
_ctc_asw_datapath_get_gport_id(uint8 lchip, uint8 sedes_id, uint32* p_gport)
{
    if (CTC_CHIP_SERDES_NONE_MODE !=  datapath_master[lchip].serdes_info[sedes_id].mode)
    {
        *p_gport = datapath_master[lchip].serdes_info[sedes_id].lport;
    }
    else
    {
        return CTC_E_NOT_INIT;
    }

    return CTC_E_NONE;
}

int32
_ctc_asw_datapath_get_gports(uint8 lchip, uint32* p_gport,uint32* p_cnt)
{
    uint8 index = 0;

    *p_cnt = 0;
    for(index=0;index<CTC_ASW_MAX_PHY_PORT;index++)
    {
        if (CTC_CHIP_SERDES_NONE_MODE !=  datapath_master[lchip].port_attr[index].pcs_mode)
        {
            p_gport[(*p_cnt)++] = index;
        }
    }

    return CTC_E_NONE;
}

int32
_ctc_asw_chip_serdes_set_cdr(uint8 lchip, uint8 serdes_id, uint16 cdr)
{
    _ctc_chip_serdes_write(lchip, serdes_id, CTC_ASW_SERDES_ADDRESS(serdes_id, 0x103), cdr);
    _ctc_chip_serdes_write(lchip, serdes_id, CTC_ASW_SERDES_ADDRESS(serdes_id, 0x10e), cdr);

	return 0;
}


#define ______DATAPATH_API______
/**
 @brief Initialize the chip module and set the local chip number of the linecard
*/
int32
ctc_asw_datapath_init(uint8 lchip, void* p_global_cfg)
{
    int32 ret = 0;
    uint32 cmd = 0;
    uint8 lport = 0;
    uint8 idx = 0;
    uint32 phy_val = 0;
    uint32 serdes_val = 0;
    uint32 qsgmii_val = 0;
    uint32 sgmii_val = 0;
    uint32 fxmii_val = 0;
    uint32 devid = 0;
    ds_t ds;
    ctc_datapath_global_cfg_t* p_datapath_cfg = NULL;

    CTC_PTR_VALID_CHECK(p_global_cfg);
    p_datapath_cfg = (ctc_datapath_global_cfg_t*)p_global_cfg;

    datapath_master[lchip].core_freq = p_datapath_cfg->core_frequency_a;
    /*check serdes mode*/
    for (idx=0; idx<CTC_ASW_MAX_SERDES_NUM; idx++)
    {
        if((((CTC_CHIP_SERDES_PHY_MODE != p_datapath_cfg->serdes[idx].mode)) && CTC_ASW_SERDES_IS_PHY(idx))
        || (((CTC_CHIP_SERDES_100BASEFX_MODE != p_datapath_cfg->serdes[idx].mode) && (CTC_CHIP_SERDES_SGMII_MODE != p_datapath_cfg->serdes[idx].mode)
           && (CTC_CHIP_SERDES_NONE_MODE != p_datapath_cfg->serdes[idx].mode)) && CTC_ASW_SERDES_IS_SOUTH_HSS(idx))
        || (((CTC_CHIP_SERDES_QSGMII_MODE != p_datapath_cfg->serdes[idx].mode) && (CTC_CHIP_SERDES_100BASEFX_MODE != p_datapath_cfg->serdes[idx].mode)
           && (CTC_CHIP_SERDES_SGMII_MODE != p_datapath_cfg->serdes[idx].mode) && (CTC_CHIP_SERDES_NONE_MODE != p_datapath_cfg->serdes[idx].mode)) && CTC_ASW_SERDES_IS_NORTH_HSS(idx)))
        {
            return CTC_E_INVALID_PARAM;
        }
    }
    /*init port attribute to rsv port default*/
    for (lport = 0; lport < CTC_ASW_MAX_PHY_PORT; lport++)
    {
        datapath_master[lchip].port_attr[lport].port_type = CTC_ASW_DATAPATH_RSV_PORT;
    }

	/* step1: config PowerMode */
    for (idx=0; idx<CTC_ASW_MAX_SERDES_NUM; idx++)
    {
        _ctc_asw_datapath_build_serdes_info(lchip, idx, p_datapath_cfg->serdes[idx].mode);
        if ((CTC_CHIP_SERDES_PHY_MODE == p_datapath_cfg->serdes[idx].mode)
            && (idx>=CTC_ASW_MAX_NORMAL_SERDES_NUM))
        {
            CTC_BIT_SET(phy_val, idx-CTC_ASW_MAX_NORMAL_SERDES_NUM);
        }
        else if ((CTC_CHIP_SERDES_NONE_MODE != p_datapath_cfg->serdes[idx].mode)
            && (idx < CTC_ASW_MAX_NORMAL_SERDES_NUM))
        {
            CTC_BIT_SET(serdes_val, (idx));
            if (CTC_CHIP_SERDES_SGMII_MODE == p_datapath_cfg->serdes[idx].mode)
            {
                CTC_BIT_SET(sgmii_val, idx);
            }
            else if ((CTC_CHIP_SERDES_QSGMII_MODE == p_datapath_cfg->serdes[idx].mode)
                    && (CTC_ASW_SERDES_IS_NORTH_HSS(idx)))
            {
                CTC_BIT_SET(qsgmii_val, idx-4);
            }
            else
            {
                CTC_BIT_SET(fxmii_val, idx);
            }
            
        }
    }

    sal_memset(&ds, 0, sizeof(ds));
    cmd= DRV_IOW(CpuMacMode_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ds));

    cmd = DRV_IOR(DeviceId_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, 0, cmd, &devid);
    
    cmd = DRV_IOR(PowerMode_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    /* step1.1: power on internal phy */
    SetPowerMode(V, enablePhy_f, &ds, (0 == ((devid>>16) & 0xF))?(phy_val&0xF):(phy_val));
    /* step1.2: power on hss */
    SetPowerMode(V, enableHss_f, &ds, serdes_val);
    cmd = DRV_IOW(PowerMode_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    sal_task_sleep(10);
    /*modify cdr*/
    for (idx=0; idx<CTC_ASW_MAX_NORMAL_SERDES_NUM; idx++)
    {
        if (!CTC_IS_BIT_SET(serdes_val, idx))
        {
            continue;
        }
        _ctc_asw_chip_serdes_set_cdr(lchip, idx, 0x4f80);
    }
	/* step1.3: config tuneFineCdr */
	/* init value: 0xf0, nothing to do */


	/* step2: config EnClkSwitch */
	/* init value: 0xfff, nothing to do */


    /* step3: config EnClkCpuSub*/
    cmd = DRV_IOR(EnClkCpuSub_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    SetEnClkCpuSub(V, enClkRegGlobal_f, &ds, 1);
    SetEnClkCpuSub(V, cfgEnClkSysDma_f, &ds, 0);
    SetEnClkCpuSub(V, cfgEnClkUsi0_f, &ds, 0);
    SetEnClkCpuSub(V, cfgEnClkUsi1_f, &ds, 0);
    cmd = DRV_IOW(EnClkCpuSub_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

	/* step4: release phy/pcs/serdes/mac */
    /*default set ResetCtlGmii all 1*/
    sal_memset(&ds, 0xFF, sizeof(ds));
    cmd = DRV_IOW(ResetCtlGmii_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    /* step4.1.1: release rx gmii */
    cmd = DRV_IOR(ResetCtlGmii_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip,0,cmd,&ds);
    for(idx=0;idx<CTC_ASW_INTERNAL_PHY_PORT_NUM; idx++)
    {
        SetResetCtlGmii(V, cfgResetGmii0Rx_f+idx*(ResetCtlGmii_cfgResetGmii1Rx_f-ResetCtlGmii_cfgResetGmii0Rx_f), &ds, 0);
    }
    cmd = DRV_IOW(ResetCtlGmii_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    /* step4.1.2: release phy */
    cmd = DRV_IOR(ResetCtlNet_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    if (phy_val&0xF)
    {
        SetResetCtlNet(V, cfgResetPhy0_f, &ds, 0);
    }
    if ((phy_val>>4)&0xF)
    {
        SetResetCtlNet(V, cfgResetPhy1_f, &ds, 0);
    }
    cmd = DRV_IOW(ResetCtlNet_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    /* step4.1.3: release tx gmii */
    cmd = DRV_IOR(ResetCtlGmii_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    for(idx=0;idx<CTC_ASW_INTERNAL_PHY_PORT_NUM; idx++)
    {
        SetResetCtlGmii(V, cfgResetGmii0Tx_f+idx*(ResetCtlGmii_cfgResetGmii1Tx_f-ResetCtlGmii_cfgResetGmii0Tx_f), &ds, 0);
    }
    cmd = DRV_IOW(ResetCtlGmii_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    /* step4.1.4: choose pcs mode by port mode */
    cmd = DRV_IOR(QsgmiiMode_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    SetQsgmiiMode(V, modeQsgmii_f, &ds, qsgmii_val);
    cmd = DRV_IOW(QsgmiiMode_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    cmd = DRV_IOR(SgmiiMode_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    SetSgmiiMode(V, modeSgmii_f, &ds,sgmii_val);
    cmd = DRV_IOW(SgmiiMode_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    cmd = DRV_IOR(FxmiiMode_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    SetFxmiiMode(V, modeFxmii_f, &ds,fxmii_val);
    cmd = DRV_IOW(FxmiiMode_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    /* step4.2: release port without internal phy */
    /* external phy reset first ???*/
    /* step4.2.1: release qsgmii/sgmii */
    for (idx=0; idx<CTC_ASW_MAX_NORMAL_SERDES_NUM; idx++)
    {
        ret = ret?ret:_ctc_asw_datapath_release_pcs(lchip, idx, 0);
        ret = ret?ret:_ctc_asw_datapath_release_pcs(lchip, idx, 1);
        ret = ret?ret:_ctc_asw_datapath_serdes_reset(lchip, idx);
    }

    /* step4.2.2: release rx gmii */
    cmd = DRV_IOR(ResetCtlGmii_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    for(idx=CTC_ASW_INTERNAL_PHY_PORT_NUM; idx<CTC_ASW_MAX_PHY_PORT; idx++)
    {
        SetResetCtlGmii(V, cfgResetGmii0Rx_f+idx*(ResetCtlGmii_cfgResetGmii1Rx_f-ResetCtlGmii_cfgResetGmii0Rx_f), &ds, 0);
    }
    cmd = DRV_IOW(ResetCtlGmii_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    /* step4.2.3: release hss */
    cmd = DRV_IOR(ResetCtlNet_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    if (serdes_val&0x3)
    {
        SetResetCtlNet(V, cfgResetHss0_f, &ds, 0);
    }
    if ((serdes_val>>2)&0x3)
    {
        SetResetCtlNet(V, cfgResetHss1_f, &ds, 0);
    }
    if ((serdes_val>>4)&0x3)
    {
        SetResetCtlNet(V, cfgResetHss2_f, &ds, 0);
    }
    if ((serdes_val>>6)&0x3)
    {
        SetResetCtlNet(V, cfgResetHss3_f, &ds, 0);
    }
    /*release cpumac*/
    SetResetCtlNet(V, cfgResetRgmii_f, &ds, 0);
    cmd = DRV_IOW(ResetCtlNet_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    /* step4.2.4: release tx gmii */
    cmd = DRV_IOR(ResetCtlGmii_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    for (idx=CTC_ASW_INTERNAL_PHY_PORT_NUM; idx<CTC_ASW_MAX_PHY_PORT; idx++)
    {
        SetResetCtlGmii(V, cfgResetGmii0Tx_f+idx*(ResetCtlGmii_cfgResetGmii1Tx_f-ResetCtlGmii_cfgResetGmii0Tx_f), &ds, 0);
    }
    SetResetCtlGmii(V, cfgResetCpuGmiiRx_f, &ds, 0);
    SetResetCtlGmii(V, cfgResetCpuGmiiTx_f, &ds, 0);
    cmd = DRV_IOW(ResetCtlGmii_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

	/* step5: release switch */
    cmd = DRV_IOR(ResetCtlCpuSub_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    SetResetCtlCpuSub(V, cfgResetSwitch_f, &ds, 1);
    cmd = DRV_IOW(ResetCtlCpuSub_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    SetResetCtlCpuSub(V, cfgResetSwitch_f, &ds, 0);
    cmd = DRV_IOW(ResetCtlCpuSub_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

	/* step6: release LinkPulse for auto-neg */
    for (idx=0; idx<CTC_ASW_MAX_NORMAL_SERDES_NUM; idx++)
    {
        ret = ret?ret:_ctc_asw_datapath_release_auto_neg(lchip, idx);
        /* stpe8: release and reset qsgmii 4 lane.because the 4 lane must first all relese */
        if (CTC_CHIP_SERDES_QSGMII_MODE == datapath_master[lchip].serdes_info[idx].mode)
        {
            cmd = DRV_IOR(QsgmiiPcsSoftRst_t, DRV_ENTRY_FLAG);
            ret = ret?ret:DRV_IOCTL(lchip, idx-4, cmd, &ds);
            SetQsgmiiPcsSoftRst(V, qsgmiiPcsRxSoftRst0_f, &ds, 0);
            SetQsgmiiPcsSoftRst(V, qsgmiiPcsRxSoftRst1_f, &ds, 0);
            SetQsgmiiPcsSoftRst(V, qsgmiiPcsRxSoftRst2_f, &ds, 0);
            SetQsgmiiPcsSoftRst(V, qsgmiiPcsRxSoftRst3_f, &ds, 0);
            cmd = DRV_IOW(QsgmiiPcsSoftRst_t, DRV_ENTRY_FLAG);
            ret = ret?ret:DRV_IOCTL(lchip, idx-4, cmd, &ds);
        }
    }

    return ret;
}

#define ______PHY_INTERNAL_____
STATIC int32
_ctc_asw_peri_phy_driver_probe(uint8 lchip, uint32 gport, uint8 type)
{
    uint8 found = 0;
    uint32 phy_id;
    ctc_chip_mdio_para_t para;
    uint8 idx = 0;
    int32 ret = CTC_E_NONE;

    sal_memset(&para, 0, sizeof(ctc_chip_mdio_para_t));
    para.bus = chip_master[lchip].port_mdio_mapping_tbl[gport];
    para.phy_addr = chip_master[lchip].port_phy_mapping_tbl[gport];

    if (para.bus == 0xFF)
    {
        phy_id = CTC_CHIP_PHY_NULL_PHY_ID;
    }
    else
    {
        /*regiser 2 high 16bits, register 3 low 16bits*/
        para.reg = 2;
        CTC_MDIO_LOCK(lchip);
        ret = _ctc_asw_chip_mdio_read(lchip, type, &para);
        phy_id = para.value<<16;
        para.reg = 3;
        ret = ret ?ret:(_ctc_asw_chip_mdio_read(lchip, type, &para));
        CTC_MDIO_UNLOCK(lchip);
        CTC_ERROR_RETURN(ret);
        phy_id = phy_id|para.value;
    }

    for(idx =0; idx<CTC_ASW_CHIP_PHY_MAX_SHIM; idx++)
    {
        if (CTC_IS_BIT_SET(chip_master[lchip].phy_shim_bitmap, idx)
           &&((chip_master[lchip].phy_shim[idx].phy_id&chip_master[lchip].phy_shim[idx].phy_id_mask) == (phy_id&chip_master[lchip].phy_shim[idx].phy_id_mask)))
        {
            found = 1;
            break;
        }
    }

    if (1 == found)
    {
        chip_master[lchip].port_phy_shim_idx[gport] = idx;
        return CTC_E_NONE;
    }

    return CTC_E_NOT_EXIST;
}

STATIC int32
_ctc_asw_peri_set_phy_mapping(uint8 lchip, ctc_chip_phy_mapping_para_t* phy_mapping_para)
{
    CTC_PTR_VALID_CHECK(phy_mapping_para);

    sal_memcpy(chip_master[lchip].port_mdio_mapping_tbl, phy_mapping_para->port_mdio_mapping_tbl,
               CTC_ASW_MAX_PORT_NUM_PER_CHIP);

    sal_memcpy(chip_master[lchip].port_phy_mapping_tbl, phy_mapping_para->port_phy_mapping_tbl,
               CTC_ASW_MAX_PORT_NUM_PER_CHIP);

    return CTC_E_NONE;
}

/**
 @brief get phy to port mapping
*/
STATIC int32
_ctc_asw_peri_get_phy_mapping(uint8 lchip, ctc_chip_phy_mapping_para_t* p_phy_mapping_para)
{
    CTC_PTR_VALID_CHECK(p_phy_mapping_para);

    sal_memcpy(p_phy_mapping_para->port_mdio_mapping_tbl,  chip_master[lchip].port_mdio_mapping_tbl,
               CTC_ASW_MAX_PORT_NUM_PER_CHIP);

    sal_memcpy(p_phy_mapping_para->port_phy_mapping_tbl,  chip_master[lchip].port_phy_mapping_tbl,
               CTC_ASW_MAX_PORT_NUM_PER_CHIP);

    return CTC_E_NONE;
}

void
_ctc_asw_chip_phy_link_event_polling_cb(uint8 lchip, uint8 start_idx, uint8 end_idx)
{
    uint8 link_status_change = 0;
    uint16 lport =0;
    uint32 value = 0;
    uint8 shim_idx = 0;
    uint32 auto_neg_mode = 0;
    uint32 auto_neg_en = 0;
    uint32 speed = 0;
    ctc_chip_mdio_para_t para;
    ctc_port_link_status_t port_link_status;
    CTC_INTERRUPT_EVENT_FUNC cb = NULL;

    sal_memset(&port_link_status, 0, sizeof(port_link_status));
    _ctc_asw_intr_get_event_func(lchip, CTC_EVENT_PORT_LINK_CHANGE, &cb);
    for (lport = start_idx; lport < end_idx; lport++)
    {
        link_status_change = 0;
        CTC_API_LOCK_THREAD(lchip);
        _ctc_asw_peri_get_phy_prop(lchip, lport, CTC_PORT_PROP_LINK_UP, (void*)&value);
        shim_idx = chip_master[lchip].port_phy_shim_idx[lport];
        if (CTC_ASW_INVALID_PHY_SHIM_IDX != shim_idx)
        {
            if (value != chip_master[lchip].link_status[lport])
            {
                link_status_change = 1;
            }
        }
        if (0 == link_status_change)
        {
            CTC_API_UNLOCK_THREAD(lchip);
            continue;
        }
        sal_memset(&para, 0, sizeof(ctc_chip_mdio_para_t));
        para.bus = chip_master[lchip].port_mdio_mapping_tbl[lport];
        para.phy_addr = chip_master[lchip].port_phy_mapping_tbl[lport];
    
        chip_master[lchip].link_status[lport] = value;

        _ctc_asw_mac_set_property(lchip, lport, CTC_PORT_PROP_MAC_EN, value);
        /*auto neg enable and linkup, set mac speed*/
        if (value)
        {
            _ctc_asw_mac_get_property(lchip, lport, CTC_PORT_PROP_SPEED, &speed);
            if ((CTC_PORT_SPEED_1G == speed) || (CTC_PORT_SPEED_100M == speed) || (CTC_PORT_SPEED_10M == speed))
            {
                _ctc_asw_mac_get_property(lchip, lport, CTC_PORT_PROP_AUTO_NEG_EN, &auto_neg_en);
                if (auto_neg_en)
                {
                    _ctc_asw_mac_get_property(lchip, lport, CTC_PORT_PROP_AUTO_NEG_MODE, &auto_neg_mode);
                    if (CTC_PORT_AUTO_NEG_MODE_SGMII_SLAVER == auto_neg_mode)
                    {
                        _ctc_asw_mac_set_property(lchip, lport, CTC_PORT_PROP_SPEED, speed);
                    }
                 }
            }
        }

        if (value)
        {
            if (chip_master[lchip].phy_shim[shim_idx].driver.linkup_event)
            {
                chip_master[lchip].phy_shim[shim_idx].driver.linkup_event(lchip, &para, chip_master[lchip].phy_shim[shim_idx].user_data);
            }
        }
        else
        {
            if (chip_master[lchip].phy_shim[shim_idx].driver.linkdown_event)
            {
                chip_master[lchip].phy_shim[shim_idx].driver.linkdown_event(lchip, &para, chip_master[lchip].phy_shim[shim_idx].user_data);
            }
        }
        CTC_API_UNLOCK_THREAD(lchip);
        if (cb && (lport < CTC_ASW_INTERNAL_PHY_PORT_NUM))
        {
            port_link_status.gport = lport;
            cb(lchip, &port_link_status);
        }
    }
}

STATIC void
_ctc_asw_chip_phy_link_event_polling(void* p_data)
{
    uint32 value = 0;
    uint8 lchip = 0;
    uint16 interval = 0;

    value = (uintptr)p_data;
    lchip = value&0xFF;
    interval = (value>>8)&0xFFFF;
    while (1)
    {
        _ctc_asw_chip_phy_link_event_polling_cb(lchip, 0, CTC_ASW_MAX_PHY_PORT);
        sal_task_sleep(interval);
    }

    return;
}

STATIC int32
_ctc_asw_chip_phy_link_monitor(uint8 lchip, uint16 interval)
{
    int32 ret = 0;
    char buffer[SAL_TASK_MAX_NAME_LEN]={0};
    uint32 value = 0;

    sal_sprintf(buffer, "ctcphyMon-%d", lchip);
    value = (interval<<8|lchip);
    if (NULL == chip_master[lchip].p_polling_task)
    {
        ret = sal_task_create(&(chip_master[lchip].p_polling_task), buffer,
                              SAL_DEF_TASK_STACK_SIZE, SAL_TASK_PRIO_DEF, _ctc_asw_chip_phy_link_event_polling, (void*)(uintptr)value);
        if (ret < 0)
        {
            return CTC_E_NOT_INIT;
        }
    }
    return CTC_E_NONE;
}


STATIC void
_ctc_asw_chip_phy_link_event_interrupt_cb(void* p_data)
{
    uint32 irq = *((uint32*)p_data);
    uint16 lchip_idx = 0;

    for (lchip_idx=0; lchip_idx<CTC_MAX_LOCAL_CHIP_NUM; lchip_idx++)
    {
        _ctc_asw_chip_phy_link_event_polling_cb(lchip_idx, CTC_ASW_INTERNAL_PHY_PORT_NUM, CTC_ASW_MAX_PHY_PORT);
    }

    if (g_dal_op.interrupt_set_en)
    {
        g_dal_op.interrupt_set_en(irq, TRUE);
    }

    return;
}

STATIC int32
_ctc_asw_peri_set_phy_register(uint8 lchip, ctc_chip_phy_shim_t* p_register)
{
    uint16 poll_interval = 0;
    int32 ret = CTC_E_NONE;
    uint8 idx = 0;
    uint8 idx_tmp = 0;

    CTC_PTR_VALID_CHECK(p_register);
    CTC_MAX_VALUE_CHECK(p_register->event_mode, CTC_CHIP_PHY_SHIM_EVENT_MODE_POLLING);
 
    for(idx =0; idx<CTC_ASW_CHIP_PHY_MAX_SHIM; idx++)
    {
        if (!CTC_IS_BIT_SET(chip_master[lchip].phy_shim_bitmap, idx))
        {
            break;
        }
    }
    if (CTC_ASW_CHIP_PHY_MAX_SHIM == idx)
    {
        return CTC_E_NO_RESOURCE;
    }
    
    sal_memcpy(&chip_master[lchip].phy_shim[idx], p_register, sizeof(ctc_chip_phy_shim_t));
    CTC_BIT_SET(chip_master[lchip].phy_shim_bitmap, idx);

    if (CTC_CHIP_PHY_SHIM_EVENT_MODE_IRQ == p_register->event_mode)
    {
        for (idx=0; idx<CTC_CHIP_PHY_MAX_IRQ_NUM && (0 != p_register->irq[idx]); idx++)
        {
            ret = g_dal_op.interrupt_register(p_register->irq[idx], SAL_TASK_PRIO_DEF, _ctc_asw_chip_phy_link_event_interrupt_cb, (void*)(uintptr)(CTC_INTR_MAX_GROUP-idx-1));
            if (ret < 0)
            {
                ret = CTC_E_NOT_EXIST;
                goto roll_back_0;
            }
        }
    }

    poll_interval = (CTC_CHIP_PHY_SHIM_EVENT_MODE_POLLING== p_register->event_mode)?p_register->poll_interval: 1000;
    _ctc_asw_chip_phy_link_monitor(lchip, poll_interval);

    return CTC_E_NONE;

roll_back_0:
    if (CTC_CHIP_PHY_SHIM_EVENT_MODE_IRQ == p_register->event_mode)
    {
        for (idx_tmp=0; idx_tmp<idx; idx_tmp++)
        {
            g_dal_op.interrupt_unregister(p_register->irq[idx_tmp]);
        }
    }
    CTC_BIT_UNSET(chip_master[lchip].phy_shim_bitmap, idx);

    return ret;
}

#define ______PHY_INTERNAL_API_____
int32
_ctc_asw_peri_set_phy_prop(uint8 lchip, uint32 gport, uint16 phy_prop_type, void* p_value)
{
    ctc_chip_mdio_type_t type = CTC_CHIP_MDIO_GE;
    ctc_chip_mdio_para_t para;
    int32 ret = CTC_E_NONE;
    uint8 phy_shim_idx = 0;
    
    sal_memset(&para, 0, sizeof(ctc_chip_mdio_para_t));
    para.bus = chip_master[lchip].port_mdio_mapping_tbl[gport];
    para.phy_addr = chip_master[lchip].port_phy_mapping_tbl[gport];

    phy_shim_idx = chip_master[lchip].port_phy_shim_idx[gport];
    if (CTC_ASW_INVALID_PHY_SHIM_IDX == phy_shim_idx)
    {
        CTC_ERROR_GOTO(_ctc_asw_peri_phy_driver_probe(lchip, gport, type), ret, roll_back);
        phy_shim_idx = chip_master[lchip].port_phy_shim_idx[gport];
    }
    switch(phy_prop_type)
    {
        case CTC_PORT_PROP_PHY_INIT:
            {
                uint32 value = 0;
                value = *((uint32*)p_value);
                if (chip_master[lchip].phy_shim[phy_shim_idx].driver.init && value)
                {
                    CTC_ERROR_GOTO(chip_master[lchip].phy_shim[phy_shim_idx].driver.init(lchip, &para), ret, roll_back);
                }
                else if ((chip_master[lchip].phy_shim[phy_shim_idx].driver.deinit) && (0 == value))
                {
                    CTC_ERROR_GOTO(chip_master[lchip].phy_shim[phy_shim_idx].driver.deinit(lchip, &para), ret, roll_back);
                    chip_master[lchip].port_phy_shim_idx[gport] = CTC_ASW_INVALID_PHY_SHIM_IDX;
                }
                else
                {
                    return CTC_E_INVALID_PARAM;
                }
            }
            break;
        case CTC_PORT_PROP_PHY_EN:
            if (chip_master[lchip].phy_shim[phy_shim_idx].driver.set_port_en)
            {
                CTC_ERROR_GOTO(chip_master[lchip].phy_shim[phy_shim_idx].driver.set_port_en(lchip, &para, *((uint32*)p_value)), ret, roll_back);
            }
            break;
        case CTC_PORT_PROP_PHY_DUPLEX:
            if (chip_master[lchip].phy_shim[phy_shim_idx].driver.set_port_duplex_en)
            {
                CTC_ERROR_GOTO(chip_master[lchip].phy_shim[phy_shim_idx].driver.set_port_duplex_en(lchip, &para, *((uint32*)p_value)), ret, roll_back);
            }
            break;
        case CTC_PORT_PROP_PHY_MEDIUM:
            if (chip_master[lchip].phy_shim[phy_shim_idx].driver.set_port_medium)
            {
                CTC_ERROR_GOTO(chip_master[lchip].phy_shim[phy_shim_idx].driver.set_port_medium(lchip, &para, *((uint32*)p_value)), ret, roll_back);
            }
            break;
        case CTC_PORT_PROP_PHY_LOOPBACK:
            if (chip_master[lchip].phy_shim[phy_shim_idx].driver.set_port_loopback)
            {
                CTC_ERROR_GOTO(chip_master[lchip].phy_shim[phy_shim_idx].driver.set_port_loopback(lchip, &para, *((uint32*)p_value)), ret, roll_back);
            }
            break;

        case CTC_PORT_PROP_PHY_AUTO_NEG_EN:
            if (chip_master[lchip].phy_shim[phy_shim_idx].driver.set_port_auto_neg_en)
            {
                CTC_ERROR_GOTO(chip_master[lchip].phy_shim[phy_shim_idx].driver.set_port_auto_neg_en(lchip, &para, *((uint32*)p_value)), ret, roll_back);
            }
            break;
        case CTC_PORT_PROP_PHY_SPEED:
            if (chip_master[lchip].phy_shim[phy_shim_idx].driver.set_port_speed)
            {
                CTC_ERROR_GOTO(chip_master[lchip].phy_shim[phy_shim_idx].driver.set_port_speed(lchip, &para, *((uint32*)p_value)), ret, roll_back);
            }
            break;
        case CTC_PORT_PROP_UNIDIR_EN:
            if (chip_master[lchip].phy_shim[phy_shim_idx].driver.set_port_unidir_en)
            {
                CTC_ERROR_GOTO(chip_master[lchip].phy_shim[phy_shim_idx].driver.set_port_unidir_en(lchip, &para, *((uint32*)p_value)), ret, roll_back);
            }
            break;
        default:
            if ((phy_prop_type >= CTC_PORT_PROP_PHY_CUSTOM_BASE) && (phy_prop_type <= CTC_PORT_PROP_PHY_CUSTOM_MAX_TYPE))
            {
                if (chip_master[lchip].phy_shim[phy_shim_idx].driver.set_ext_attr)
                {
                    CTC_ERROR_GOTO(chip_master[lchip].phy_shim[phy_shim_idx].driver.set_ext_attr(lchip, &para, phy_prop_type, p_value), ret, roll_back);
                }
            }
            else
            {
                return CTC_E_INVALID_PARAM;
            }

    }

roll_back:
    return ret;
}

int32
_ctc_asw_peri_get_phy_prop(uint8 lchip, uint32 gport, uint16 phy_prop_type, void* p_value)
{
    ctc_chip_mdio_para_t para;
    int32 ret = CTC_E_NONE;
    uint8 phy_shim_idx = 0;

    sal_memset(&para, 0, sizeof(ctc_chip_mdio_para_t));

    phy_shim_idx = chip_master[lchip].port_phy_shim_idx[gport];
    if (CTC_ASW_INVALID_PHY_SHIM_IDX == phy_shim_idx)
    {
        return CTC_E_NOT_INIT;
    }

    para.bus = chip_master[lchip].port_mdio_mapping_tbl[gport];
    para.phy_addr = chip_master[lchip].port_phy_mapping_tbl[gport];

    switch(phy_prop_type)
    {
        case CTC_PORT_PROP_PHY_EN:
            if (chip_master[lchip].phy_shim[phy_shim_idx].driver.get_port_en)
            {
                CTC_ERROR_GOTO(chip_master[lchip].phy_shim[phy_shim_idx].driver.get_port_en(lchip, &para, (uint32*)p_value), ret, roll_back);
            }
            break;
        case CTC_PORT_PROP_PHY_DUPLEX:
            if (chip_master[lchip].phy_shim[phy_shim_idx].driver.get_port_duplex_en)
            {
                CTC_ERROR_GOTO(chip_master[lchip].phy_shim[phy_shim_idx].driver.get_port_duplex_en(lchip, &para, (uint32*)p_value), ret, roll_back);
            }
            break;
        case CTC_PORT_PROP_PHY_MEDIUM:
            if (chip_master[lchip].phy_shim[phy_shim_idx].driver.get_port_medium)
            {
                CTC_ERROR_GOTO(chip_master[lchip].phy_shim[phy_shim_idx].driver.get_port_medium(lchip, &para, (uint32*)p_value), ret, roll_back);
            }
            break;
        case CTC_PORT_PROP_PHY_LOOPBACK:
            if (chip_master[lchip].phy_shim[phy_shim_idx].driver.get_port_loopback)
            {
                CTC_ERROR_GOTO(chip_master[lchip].phy_shim[phy_shim_idx].driver.get_port_loopback(lchip, &para, (uint32*)p_value), ret, roll_back);
            }
            break;

        case CTC_PORT_PROP_PHY_AUTO_NEG_EN:
            if (chip_master[lchip].phy_shim[phy_shim_idx].driver.get_port_auto_neg_en)
            {
                CTC_ERROR_GOTO(chip_master[lchip].phy_shim[phy_shim_idx].driver.get_port_auto_neg_en(lchip, &para, (uint32*)p_value), ret, roll_back);
            }
            break;
        case CTC_PORT_PROP_PHY_SPEED:
            if (chip_master[lchip].phy_shim[phy_shim_idx].driver.get_port_speed)
            {
                CTC_ERROR_GOTO(chip_master[lchip].phy_shim[phy_shim_idx].driver.get_port_speed(lchip, &para, (uint32*)p_value), ret, roll_back);
            }
            break;
        case CTC_PORT_PROP_LINK_UP:
            if (chip_master[lchip].phy_shim[phy_shim_idx].driver.get_link_up_status)
            {
                CTC_ERROR_GOTO(chip_master[lchip].phy_shim[phy_shim_idx].driver.get_link_up_status(lchip, &para, (uint32*)p_value), ret, roll_back);
            }
            break;
        case CTC_PORT_PROP_UNIDIR_EN:
            if (chip_master[lchip].phy_shim[phy_shim_idx].driver.get_port_unidir_en)
            {
                CTC_ERROR_GOTO(chip_master[lchip].phy_shim[phy_shim_idx].driver.get_port_unidir_en(lchip, &para, (uint32*)p_value), ret, roll_back);
            }
            break;
        default:
            if ((phy_prop_type >= CTC_PORT_PROP_PHY_CUSTOM_BASE) && (phy_prop_type <= CTC_PORT_PROP_PHY_CUSTOM_MAX_TYPE))
            {
                if (chip_master[lchip].phy_shim[phy_shim_idx].driver.get_ext_attr)
                {
                    CTC_ERROR_GOTO(chip_master[lchip].phy_shim[phy_shim_idx].driver.get_ext_attr(lchip, &para, phy_prop_type, p_value), ret, roll_back);
                }
            }
            else
            {
                return CTC_E_INVALID_PARAM;
            }
    }

roll_back:
    return ret;
}

int32
_ctc_asw_peri_get_phy_id(uint8 lchip, uint32 gport, uint32* phy_id)
{
    uint8 phy_shim_idx = 0;

    phy_shim_idx = chip_master[lchip].port_phy_shim_idx[gport];
    if (CTC_ASW_INVALID_PHY_SHIM_IDX != phy_shim_idx)
    {
        *phy_id = (chip_master[lchip].phy_shim[phy_shim_idx].phy_id & chip_master[lchip].phy_shim[phy_shim_idx].phy_id_mask);
    }
    else
    {
        return CTC_E_NOT_INIT;
    }

    return CTC_E_NONE;

}

int32
_ctc_asw_peri_get_phy_register_exist(uint8 lchip, uint32 gport)
{
    if (CTC_ASW_INVALID_PHY_SHIM_IDX != chip_master[lchip].port_phy_shim_idx[gport])
    {
        return CTC_E_NONE;
    }

    return CTC_E_NOT_INIT;
}

#define ______CHIP_INERNAL_____
STATIC int32
_ctc_asw_get_chip_clock(uint8 lchip, uint16* freq)
{
    *freq = datapath_master[lchip].core_freq;

    return CTC_E_NONE;
}

STATIC int32
_ctc_asw_chip_led_mode_cfg(ctc_chip_led_mode_t mode, uint32 *value)
{
    uint32 temp;
    switch(mode)
    {
        case CTC_CHIP_RXLINK_MODE:
            temp = (CTC_ASW_CHIP_LED_ON_RX_LINK & 0x3)
                | ((CTC_ASW_CHIP_LED_BLINK_OFF & 0x3) << 2);
            break;

        case CTC_CHIP_TXLINK_MODE:
            temp = (CTC_ASW_CHIP_LED_ON_TX_LINK & 0x3)
                | ((CTC_ASW_CHIP_LED_BLINK_OFF & 0x3) << 2);
            break;

        case CTC_CHIP_RXLINK_RXACTIVITY_MODE:
            temp = (CTC_ASW_CHIP_LED_ON_RX_LINK & 0x3)
                | ((CTC_ASW_CHIP_LED_BLINK_RX_ACT & 0x3) << 2);
            break;

        case CTC_CHIP_TXLINK_TXACTIVITY_MODE:
            temp = (CTC_ASW_CHIP_LED_ON_TX_LINK & 0x3)
                | ((CTC_ASW_CHIP_LED_BLINK_TX_ACT & 0x3) << 2);
            break;

        case CTC_CHIP_RXLINK_BIACTIVITY_MODE:
            temp = (CTC_ASW_CHIP_LED_ON_RX_LINK & 0x3)
                | ((CTC_ASW_CHIP_LED_BLINK_ON & 0x3) << 2);
            break;

        case CTC_CHIP_TXACTIVITY_MODE:
            temp = (CTC_ASW_CHIP_LED_FORCE_OFF & 0x3)
                | ((CTC_ASW_CHIP_LED_BLINK_TX_ACT & 0x3) << 2);
            break;

        case CTC_CHIP_RXACTIVITY_MODE:
            temp = (CTC_ASW_CHIP_LED_FORCE_OFF & 0x3)
                | ((CTC_ASW_CHIP_LED_BLINK_RX_ACT & 0x3) << 2);
            break;

        case CTC_CHIP_BIACTIVITY_MODE:
            temp = (CTC_ASW_CHIP_LED_FORCE_OFF & 0x3)
                | ((CTC_ASW_CHIP_LED_BLINK_ON & 0x3) << 2);
            break;

        case CTC_CHIP_FORCE_ON_MODE:
            temp = (CTC_ASW_CHIP_LED_FORCE_ON & 0x3)
                | ((CTC_ASW_CHIP_LED_BLINK_OFF & 0x3) << 2);
            break;

        case CTC_CHIP_FORCE_OFF_MODE:
            temp = (CTC_ASW_CHIP_LED_FORCE_OFF & 0x3)
                | ((CTC_ASW_CHIP_LED_BLINK_OFF & 0x3) << 2);
            break;

       case CTC_CHIP_FORCE_ON_TXACTIVITY_MODE:
            temp = (CTC_ASW_CHIP_LED_FORCE_ON & 0x3)
                | ((CTC_ASW_CHIP_LED_BLINK_TX_ACT & 0x3) << 2);
            break;

       case CTC_CHIP_FORCE_ON_RXACTIVITY_MODE:
            temp = (CTC_ASW_CHIP_LED_FORCE_ON & 0x3)
                | ((CTC_ASW_CHIP_LED_BLINK_RX_ACT & 0x3) << 2);
            break;

       case CTC_CHIP_FORCE_ON_BIACTIVITY_MODE:
            temp = (CTC_ASW_CHIP_LED_FORCE_ON & 0x3)
                | ((CTC_ASW_CHIP_LED_BLINK_ON & 0x3) << 2);
            break;

        default:
            return CTC_E_INVALID_PARAM;
    }

    *value = temp;

    return 0;
}

/**
 @brief set mac led enable
*/
/* Led setting for clockcore = 125MHz */
#define CTC_MAC_LED_REFRESH_INTERVAL	0x855552
#define CTC_MAC_LED_SAMPLE_INTERVAL	0x3616392
#define CTC_MAC_LED_BLINK_INTERVAL	0x2BB5C77
STATIC int32
_ctc_asw_chip_set_mac_led_en(uint8 lchip, bool enable)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    ds_t ds;
    uint32 refresh_interval = CTC_MAC_LED_REFRESH_INTERVAL;
    uint32 sample_interval = CTC_MAC_LED_SAMPLE_INTERVAL;

    /* disable walkerstop function */
    cmd = DRV_IOR(LedCfgCalCtl_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip,0,cmd,&ds);
    SetLedCfgCalCtl(V, walkerStop_f, &ds, 0);
    cmd = DRV_IOW(LedCfgCalCtl_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    /* disable LedRawStatusCfg */
    cmd = DRV_IOR(LedRawStatusCfg_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    SetLedRawStatusCfg(V, rawStatusEn_f, &ds, 0);
    cmd = DRV_IOW(LedRawStatusCfg_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    /* set sample interval */
    cmd = DRV_IOR(LedSampleInterval_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    SetLedSampleInterval(V, sampleInterval_f, &ds, sample_interval);
    cmd = DRV_IOW(LedSampleInterval_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    /* set refresh interval */
    cmd = DRV_IOR(LedRefreshInterval_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    SetLedRefreshInterval(V, refreshInterval_f, &ds, refresh_interval);
    cmd = DRV_IOW(LedRefreshInterval_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    cmd = DRV_IOR(LedSampleInterval_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    /* enable history sample */
    SetLedSampleInterval(V, histogramEn_f, &ds, enable?1:0);
    /* enable led sample */
    SetLedSampleInterval(V, sampleEn_f, &ds, enable?1:0);
    cmd = DRV_IOW(LedSampleInterval_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    /* enable led refresh */
    cmd = DRV_IOR(LedRefreshInterval_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    SetLedRefreshInterval(V, refreshEn_f, &ds, enable?1:0);
    cmd = DRV_IOW(LedRefreshInterval_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    /* enable ledCntSync */
    SetLedModeCtl(V, cfgLedMode_f, &ds, enable?1:0);
    cmd = DRV_IOW(LedModeCtl_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    return ret;
}

STATIC int32
_ctc_asw_chip_set_led_clock(uint8 lchip, uint32 freq)
{
    int32 ret = CTC_E_NONE;
    uint32 fld_val = 0;
    uint32 cmd = 0;
    ds_t ds;

    fld_val = CTC_ASW_CHIP_CORE_CLOCK*2/freq;
    cmd = DRV_IOR(ClkDivCfg_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip,0,cmd,&ds);
    SetClkDivCfg(V, clkDivLed_f, &ds, fld_val);
    cmd = DRV_IOW(ClkDivCfg_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    /*enable clockLed divider*/
    cmd = DRV_IOR(EnClkCpuSub_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    SetEnClkCpuSub(V, cfgEnClkLed_f, &ds, 1);
    cmd = DRV_IOW(EnClkCpuSub_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    return ret;
}

STATIC int32
_ctc_asw_chip_get_led_clock(uint8 lchip, uint32* p_freq)
{
    int32 ret = CTC_E_NONE;
    uint32 fld_val = 0;
    uint32 cmd = 0;
    ds_t ds;

    cmd = DRV_IOR(ClkDivCfg_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip,0,cmd,&ds);
    fld_val = GetClkDivCfg(V, clkDivLed_f, &ds);
    *p_freq =  CTC_ASW_CHIP_CORE_CLOCK*2/fld_val;

    return ret;
}

STATIC int32
_ctc_asw_chip_get_mac_led_en(uint8 lchip, bool* p_enable)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    ds_t ds;

    /* get refresh interval */
    cmd = DRV_IOR(LedRefreshInterval_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip,0,cmd,&ds);
    *p_enable = GetLedRefreshInterval(V, refreshEn_f, &ds);

    return ret;
}

/* set mdio clock */
STATIC int32
_ctc_asw_chip_set_mdio_clock(uint8 lchip, uint32 freq)
{
    int32 ret = CTC_E_NONE;
    uint32 div_num = 0;
    uint32 cmd = 0;
    ds_t ds;
    if(freq > CTC_ASW_CHIP_CORE_CLOCK*2)
    {
        return CTC_E_INVALID_PARAM;
    }
    /* calculate clock division number */
    div_num = CTC_ASW_CHIP_CORE_CLOCK*2/freq;

    /* set clock divider register */
    cmd = DRV_IOR(ClkDivCfg_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip,0,cmd,&ds);
    SetClkDivCfg(V, clkDivMdio_f, &ds, div_num);
    cmd = DRV_IOW(ClkDivCfg_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    /* reset clockMdio divider */
    cmd = DRV_IOR(EnClkCpuSub_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    SetEnClkCpuSub(V, cfgEnClkMdio_f, &ds, 1);
    cmd = DRV_IOW(EnClkCpuSub_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    return ret;
}

STATIC int32
_ctc_asw_chip_get_mdio_clock(uint8 lchip, uint32 *freq)
{
    int32 ret = CTC_E_NONE;
    uint32 div_num = 0;
    uint32 cmd = 0;
    ds_t ds;

    /* get clock div num */
    cmd = DRV_IOR(ClkDivCfg_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip,0,cmd,&ds);
    div_num = GetClkDivCfg(V, clkDivMdio_f, &ds);

    *freq = CTC_ASW_CHIP_CORE_CLOCK*2/div_num;

    return ret;
}

STATIC int32
_ctc_asw_chip_mdio_init(uint8 lchip)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    ds_t ds;
    uint32 default_freq = 2500;

    sal_memset(ds, 0, sizeof(ds));
    /* cfg mdio default clock to 2.5MHz,@clockCore=125MHz */
    ret = _ctc_asw_chip_set_mdio_clock(lchip, default_freq);

    /* reset Mdio moudle */
    cmd = DRV_IOR(ResetCtlCpuSub_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    SetResetCtlCpuSub(V, cfgResetMdio_f, &ds, 1);
    cmd = DRV_IOW(ResetCtlCpuSub_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    SetResetCtlCpuSub(V, cfgResetMdio_f, &ds, 0);
    cmd = DRV_IOW(ResetCtlCpuSub_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    return ret;
}

#define ______CHIP_INERNAL_API_____
int32
_ctc_asw_chip_get_cpu_port(uint8 lchip)
{
    return chip_master[lchip].cpu_port;
}

int32
_ctc_asw_init_chip_global_cfg(uint8 lchip)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    ds_t ds;
    uint8 cpu_port_en = 0;
    hw_mac_addr_t hw_mac =  {0};
    if(chip_master[lchip].cpu_port == CTC_ASW_CPU_PORT_0 || chip_master[lchip].cpu_port == CTC_ASW_CPU_PORT_1)
    {
        cpu_port_en = 1;
    }

    cmd = DRV_IOR(CpuMacCtrl_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip, 0, cmd, &ds);
    SetCpuMacCtrl(V, mode_f, &ds, 0);
    SetCpuMacCtrl(V, cpuEn_f, &ds, cpu_port_en?0x2:0x0);
    SetCpuMacCtrl(V, noPtagDrop_f, &ds, cpu_port_en?0x2:0x0);
    cmd = DRV_IOW(CpuMacCtrl_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip, 0, cmd, &ds);
    cmd = DRV_IOR(RgmiiMode_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip, 0, cmd, &ds);
    SetRgmiiMode(V, modeRgmii_f, &ds, (CTC_ASW_CPU_PORT_0 == chip_master[lchip].cpu_port)?0x0:0x1);
    cmd= DRV_IOW(RgmiiMode_t, DRV_ENTRY_FLAG);
    ret = ret?ret:(DRV_IOCTL(lchip, 0, cmd, &ds));
    
    cmd = DRV_IOR(Ptagtpid_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip, 0, cmd, &ds);
    SetPtagtpid(V, tpidCpu_f, &ds, chip_master[lchip].tpid);
    cmd = DRV_IOW(Ptagtpid_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip, 0, cmd, &ds);

    CTC_ASW_SET_HW_MAC(hw_mac, (uint8*)(chip_master[lchip].cpu_mac_da));
    cmd = DRV_IOR(SpmacUcMac_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip, 0, cmd, &ds);
    SetSpmacUcMac(A, mac_f, &ds, hw_mac);
    cmd = DRV_IOW(SpmacUcMac_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip, 0, cmd, &ds);

    return ret;
}

int32
_ctc_asw_chip_gpio_init(uint8 lchip)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    ds_t ds;
 
    /*enable clock*/
    cmd = DRV_IOR(EnClkCpuSub_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip,0,cmd,&ds);
    SetEnClkCpuSub(V, cfgEnClkGpio_f, &ds, 1);
    cmd = DRV_IOW(EnClkCpuSub_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    /* reset  gpio  moudle */
    cmd = DRV_IOR(ResetCtlCpuSub_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    SetResetCtlCpuSub(V, cfgResetGpio_f, &ds, 1);
    cmd = DRV_IOW(ResetCtlCpuSub_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    SetResetCtlCpuSub(V, cfgResetGpio_f, &ds, 0);
    cmd = DRV_IOW(ResetCtlCpuSub_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    return ret;
}

int32
_ctc_asw_chip_led_init(uint8 lchip)
{
    int32 ret = CTC_E_NONE;
    uint32 def_freq = 5000; /*5Mhz*/
    uint32 cmd = 0;
    ds_t ds;
#ifndef MEM_MODEL
    uint32 timeout = 50000;
    uint32 led_init_done = 0;
#endif
    uint32 led_blink_interval = CTC_MAC_LED_BLINK_INTERVAL;

    sal_memset(ds, 0, sizeof(ds));

    ret = _ctc_asw_chip_set_led_clock(lchip, def_freq);
    /* set led reset */
    cmd = DRV_IOR(ResetCtlCpuSub_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    SetResetCtlCpuSub(V, cfgResetLed_f, &ds, 1);
    cmd = DRV_IOW(ResetCtlCpuSub_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    SetResetCtlCpuSub(V, cfgResetLed_f, &ds, 0);
    cmd = DRV_IOW(ResetCtlCpuSub_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    /* led init */
    SetLedInit(V, init_f, &ds, 1);
    cmd = DRV_IOW(LedInit_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

#ifndef MEM_MODEL
    /* wait led init done */
    cmd = DRV_IOR(LedInitDone_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    led_init_done = GetLedInitDone(V, initDone_f, &ds);
    while((0 == led_init_done) && (timeout))
    {
        timeout --;
        cmd = DRV_IOR(LedInitDone_t, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
        led_init_done = GetLedInitDone(V, initDone_f, &ds);
        sal_task_sleep(10);
    }

    if(0 == led_init_done)
    {
        ret = CTC_E_HW_FAIL;
    }
#endif
    /* set led blinkcfg */
    cmd = DRV_IOR(LedBlinkCfg_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);
    SetLedBlinkCfg(V, blinkOffInterval_f, &ds, led_blink_interval);
    SetLedBlinkCfg(V, blinkOnInterval_f, &ds, led_blink_interval);
    cmd = DRV_IOW(LedBlinkCfg_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    return ret;
}

#define ______CHIP_API______
/**
 @brief set mac led mode interface
*/
int32
ctc_asw_chip_set_mac_led_mode(uint8 lchip, ctc_chip_led_para_t* p_led_para, ctc_chip_mac_led_type_t led_type)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    LedCfgPortMode_m led_mode;
    LedPolarityCfg_m led_polar;
    uint32 fld_val = 0;

    CTC_PTR_VALID_CHECK(p_led_para);
    CTC_MAX_VALUE_CHECK(led_type, CTC_CHIP_USING_TWO_LED);

    sal_memset(&led_mode, 0, sizeof(LedCfgPortMode_m));
    CTC_API_LOCK(lchip);
    if (CTC_FLAG_ISSET(p_led_para->op_flag, CTC_CHIP_LED_MODE_SET_OP))
    {
        ret = _ctc_asw_chip_led_mode_cfg(p_led_para->first_mode, &fld_val);
        SetLedCfgPortMode(V, primaryLedMode_f, &led_mode, fld_val);

        if(CTC_CHIP_USING_TWO_LED == led_type)
        {
            ret = ret?ret:_ctc_asw_chip_led_mode_cfg(p_led_para->sec_mode, &fld_val);
            SetLedCfgPortMode(V, secondaryLedMode_f, &led_mode, fld_val);
            SetLedCfgPortMode(V, secondaryLedModeEn_f, &led_mode, 1);
        }

        cmd = DRV_IOW(LedCfgPortMode_t, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip, p_led_para->port_id, cmd, &led_mode);
    }
    if (CTC_FLAG_ISSET(p_led_para->op_flag, CTC_CHIP_LED_POLARITY_SET_OP))
    {
        SetLedPolarityCfg(V, polarityInv_f, &led_polar, p_led_para->polarity?1:0);
        cmd = DRV_IOW(LedPolarityCfg_t, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip, 0, cmd, &led_polar);
    }
    CTC_API_UNLOCK(lchip);

    return ret;
}

/**
 @brief set mac led mapping
*/
int32
ctc_asw_chip_set_mac_led_mapping(uint8 lchip, ctc_chip_mac_led_mapping_t* p_led_map)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    uint32 index = 0;
    uint8 mac_id = 0;
    LedCfgPortSeqMap_m seq_map;
    LedPortRange_m port_range;
    uint16 lport;

    if ((p_led_map->mac_led_num > CTC_ASW_MAX_PHY_PORT) || (p_led_map->mac_led_num < 1))
    {
        return CTC_E_INVALID_PARAM;
    }

    sal_memset(&port_range, 0, sizeof(port_range));
    sal_memset(&seq_map, 0, sizeof(seq_map));

    CTC_API_LOCK(lchip);
    /* set LedCfgPortSeqMap */
    for (index = 0; index < p_led_map->mac_led_num; index ++)
    {
        if (p_led_map->lport_en)
        {
            lport = (*((uint16*)p_led_map->port_list + index));
            ret = _ctc_asw_datapath_get_mac_id_with_gport(lchip, lport, &mac_id);
        }
        else
        {
            mac_id = *((uint8*)p_led_map->p_mac_id + index);
            if (mac_id >= CTC_ASW_MAX_PHY_PORT)
            {
                CTC_API_UNLOCK(lchip);
                return CTC_E_INVALID_PARAM;
            }
        }
        cmd = DRV_IOW(LedCfgPortSeqMap_t, DRV_ENTRY_FLAG);
        SetLedCfgPortSeqMap(V, macId_f, &seq_map, mac_id);
        ret = ret?ret:DRV_IOCTL(lchip, index, cmd, &seq_map);
    }

    /* set MacLedPortRange */
    SetLedPortRange(V, portStartIndex_f, &port_range, 0);
    SetLedPortRange(V, portEndIndex_f, &port_range, p_led_map->mac_led_num - 1);
    cmd = DRV_IOW(LedPortRange_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip, 0, cmd, &port_range);
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_chip_set_mac_led_en(uint8 lchip, bool enable)
{
    int32 ret = CTC_E_NONE;
    CTC_API_LOCK(lchip);
    ret = _ctc_asw_chip_set_mac_led_en(lchip, enable);
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_chip_get_mac_led_en(uint8 lchip, bool* p_enable)
{
    int32 ret = CTC_E_NONE;

    CTC_API_LOCK(lchip);
    ret = _ctc_asw_chip_get_mac_led_en(lchip, p_enable);
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_chip_mdio_read(uint8 lchip, ctc_chip_mdio_type_t type, ctc_chip_mdio_para_t* p_para)
{
    int32 ret = CTC_E_NONE;

    CTC_PTR_VALID_CHECK(p_para);
    CTC_MAX_VALUE_CHECK(p_para->bus, 1);

    CTC_MDIO_LOCK(lchip);
    ret = _ctc_asw_chip_mdio_read(lchip, type, p_para);
    CTC_MDIO_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_chip_mdio_write(uint8 lchip, ctc_chip_mdio_type_t type, ctc_chip_mdio_para_t* p_para)
{
    int32 ret = CTC_E_NONE;

    CTC_PTR_VALID_CHECK(p_para);
    CTC_MAX_VALUE_CHECK(p_para->bus, 1);

    CTC_MDIO_LOCK(lchip);
    ret = _ctc_asw_chip_mdio_write(lchip, type, p_para);
    CTC_MDIO_UNLOCK(lchip);

    return ret;
}

/**
 @brief set gpio interface
*/
int32
ctc_asw_chip_set_gpio_mode(uint8 lchip, uint8 gpio, ctc_chip_gpio_mode_t mode)
{
    int32 ret = 0;
    uint32 cmd = 0;
    uint32 value = 0;
    ds_t ds;

    CTC_MAX_VALUE_CHECK(gpio, CTC_ASW_CHIP_MAX_GPIO_ID);
    CTC_MAX_VALUE_CHECK(mode, CTC_CHIP_MAX_GPIO_MODE-1);
    CTC_API_LOCK(lchip);

    cmd = DRV_IOR(GpioOutEn_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, 0, cmd, &ds);

    value = GetGpioOutEn(V, cfgOutEn_f, &ds);

    if (CTC_CHIP_OUTPUT_MODE == mode)
    {
        CTC_BIT_SET(value, gpio);
    }
    else
    {
        CTC_BIT_UNSET(value, gpio);
    }
    SetGpioOutEn(V, cfgOutEn_f, &ds, value);
    cmd = DRV_IOW(GpioOutEn_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    CTC_API_UNLOCK(lchip);

    return ret;
}

/**
 @brief set gpio output value
*/
int32
ctc_asw_chip_set_gpio_output(uint8 lchip, uint8 gpio, uint8 out_para)
{
    int32 ret = 0;
    uint32 cmd = 0;
    uint32 value = 0;
    ds_t ds;

    CTC_MAX_VALUE_CHECK(gpio, CTC_ASW_CHIP_MAX_GPIO_ID);
    CTC_MAX_VALUE_CHECK(out_para, CTC_ASW_CHIP_MAX_GPIO_VALUE);
    CTC_API_LOCK(lchip);

    cmd = DRV_IOR(GpioOutData_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, 0, cmd, &ds);

    value = GetGpioOutData(V, cfgOutData_f, &ds);

    if (out_para>0)
    {
        CTC_BIT_SET(value, gpio);
    }
    else
    {
        CTC_BIT_UNSET(value, gpio);
    }
    SetGpioOutData(V, cfgOutData_f, &ds, value);
    cmd = DRV_IOW(GpioOutData_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&ds);

    CTC_API_UNLOCK(lchip);

    return ret;
}

/**
 @brief set gpio output value
*/
int32
ctc_asw_chip_get_gpio_input(uint8 lchip, uint8 gpio, uint8* in_value)
{
    int32 ret = 0;
    uint32 cmd = 0;
    uint32 value = 0;
    ds_t ds;

    CTC_MAX_VALUE_CHECK(gpio, CTC_ASW_CHIP_MAX_GPIO_ID);
    CTC_API_LOCK(lchip);

    cmd = DRV_IOR(GpioReadData_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, 0, cmd, &ds);

    value = GetGpioReadData(V, gpioReadData_f, &ds);

    *in_value = (CTC_IS_BIT_SET(value, gpio))?1:0;

    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_set_chip_global_cfg(uint8 lchip, ctc_chip_global_cfg_t* chip_cfg)
{
    if(lchip>=CTC_MAX_LOCAL_CHIP_NUM) 
    {
        return CTC_E_INVALID_CHIP_ID;
    }
    CTC_PTR_VALID_CHECK(chip_cfg);
    if (chip_cfg->cpu_port_en
        && ((CTC_ASW_CPU_PORT_0 != chip_cfg->cpu_port)
        && (CTC_ASW_CPU_PORT_1 != chip_cfg->cpu_port)))
    {
        return CTC_E_INVALID_PARAM;
    }
    if(chip_cfg->cpu_port_en)
    {
        chip_master[lchip].cpu_port = chip_cfg->cpu_port;
        sal_memcpy(&chip_master[lchip].cpu_mac_da, &chip_cfg->cpu_mac_da[0], sizeof(mac_addr_t));
    }
    else
    {
        chip_master[lchip].cpu_port = 0;
    }
    chip_master[lchip].tpid = chip_cfg->tpid;
    drv_asw_set_io_wr_dis(lchip, chip_cfg->io_wr_dis);
    
    return CTC_E_NONE;
}

/**
 @brief set chip property
*/
int32
ctc_asw_chip_set_property(uint8 lchip,  ctc_chip_property_t chip_prop,  void* p_value)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    uint32 gport = 0;
    CTC_PTR_VALID_CHECK(p_value);
    CTC_API_LOCK(lchip);
    switch(chip_prop)
    {
        case CTC_CHIP_PROP_SERDES_LOOPBACK:
            {
                ctc_chip_serdes_loopback_t* p_loopback = NULL;
                ds_t ds;
                uint8 port_num = 0;
                uint8 index = 0;

                sal_memset(ds, 0, sizeof(ds));
                p_loopback = (ctc_chip_serdes_loopback_t*)p_value;

                ret = _ctc_asw_datapath_get_gport_with_serdes(lchip, p_loopback->serdes_id, &gport, &port_num);
                for(index=0; index<port_num; index++)
                {
                    if (0 == p_loopback->mode)
                    {
                        cmd = DRV_IOR(MacTxCtrl_t, DRV_ENTRY_FLAG);
                        ret = ret?ret:DRV_IOCTL(lchip, gport+index, cmd, &ds);
                        SetMacTxCtrl(V, loopbackEn_f, &ds, p_loopback->enable?1:0);
                        cmd = DRV_IOW(MacTxCtrl_t, DRV_ENTRY_FLAG);
                        ret = ret?ret:DRV_IOCTL(lchip, gport+index, cmd, &ds);
                    }
                    else
                    {
                        cmd = DRV_IOR(MacRxCtrl_t, DRV_ENTRY_FLAG);
                        ret = ret?ret:DRV_IOCTL(lchip, gport+index, cmd, &ds);
                        SetMacRxCtrl(V, loopbackEn_f, &ds, p_loopback->enable?1:0);
                        cmd = DRV_IOW(MacRxCtrl_t, DRV_ENTRY_FLAG);
                        ret = ret?ret:DRV_IOCTL(lchip, gport+index, cmd, &ds);
                    }
                }
            }
            break;
        case CTC_CHIP_PROP_SERDES_PRBS:
            {
                ctc_chip_serdes_prbs_t* p_prbs = (ctc_chip_serdes_prbs_t*)p_value;
                CTC_MAX_VALUE_CHECK_UNLOCK(p_prbs->serdes_id, CTC_ASW_MAX_NORMAL_SERDES_NUM-1);
                switch(p_prbs->mode)
                {
                    case 0: /* 0--Rx */
                        ret = _ctc_asw_datapath_set_serdes_prbs_rx(lchip, p_prbs);
                        break;
                    case 1: /* 1--Tx */
                        ret = _ctc_asw_datapath_set_serdes_prbs_tx(lchip, p_prbs);
                        break;
                    default:
                        ret = CTC_E_INVALID_PARAM;
                        break;
                }
            }
            break;
        case CTC_CHIP_PROP_SERDES_FFE:
            {
                ctc_chip_serdes_ffe_t* p_ffe = (ctc_chip_serdes_ffe_t*)p_value;
                CTC_MAX_VALUE_CHECK_UNLOCK(p_ffe->serdes_id, CTC_ASW_MAX_NORMAL_SERDES_NUM-1);
                ret = _ctc_asw_datapath_set_serdes_ffe(lchip, p_ffe);
            }
            break;
        case CTC_CHIP_PROP_PERI_CLOCK:
            {
                ctc_chip_peri_clock_t* p_clock = (ctc_chip_peri_clock_t*)p_value;
                switch(p_clock->type)
                {
                    case CTC_CHIP_PERI_MDIO_TYPE:
                        ret = _ctc_asw_chip_set_mdio_clock(lchip, p_clock->clock_val);
                        break;
                    case CTC_CHIP_PERI_MAC_LED_TYPE:
                        ret =_ctc_asw_chip_set_led_clock(lchip, p_clock->clock_val);
                        break;
                    default:
                        ret = CTC_E_INVALID_PARAM;
                        break;
                }
                break;
            }
        case CTC_CHIP_PROP_REGISTER_PHY:
            ret = _ctc_asw_peri_set_phy_register(lchip, (ctc_chip_phy_shim_t*)p_value);
            break;
        case CTC_CHIP_PROP_PHY_MAPPING:
            ret = _ctc_asw_peri_set_phy_mapping(lchip, (ctc_chip_phy_mapping_para_t*)p_value);
            break;

        case CTC_CHIP_MAC_LED_EN:
            ret = _ctc_asw_chip_set_mac_led_en(lchip, *((bool *)p_value));
            break;
        case CTC_CHIP_PROP_IO_WR_DIS:
        {
            uint32 value = *(uint32*)p_value;
            drv_asw_set_io_wr_dis(lchip, value);
            break;
        }
        case CTC_CHIP_PROP_SERDES_DFE:
        {
            ctc_chip_serdes_cfg_t* p_dfe = (ctc_chip_serdes_cfg_t*)p_value;
            CTC_MAX_VALUE_CHECK_UNLOCK(p_dfe->serdes_id, CTC_ASW_MAX_NORMAL_SERDES_NUM-1);
            CTC_MAX_VALUE_CHECK_UNLOCK(p_dfe->value, (CTC_ASW_MAX_DFE_MODE_NUM-1));
            ret = _ctc_asw_datapath_set_serdes_dfe(lchip, p_dfe);
        }
        break;

        default:
            CTC_API_UNLOCK(lchip);
            return CTC_E_INVALID_PARAM;
    }
    CTC_API_UNLOCK(lchip);

    return ret;
}


/**
 @brief get chip property
*/
int32
ctc_asw_chip_get_property(uint8 lchip,  ctc_chip_property_t chip_prop,  void* p_value)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    uint32 value = 0;

    CTC_PTR_VALID_CHECK(p_value);
    CTC_API_LOCK(lchip);
    switch(chip_prop)
    {
        case CTC_CHIP_PROP_DEVICE_INFO:
            {
                ctc_chip_device_info_t* p_device_info = (ctc_chip_device_info_t*)p_value;
                cmd = DRV_IOR(DeviceId_t, DRV_ENTRY_FLAG);
                ret = DRV_IOCTL(lchip, 0, cmd, &value);
                p_device_info->version_id = (value>>16)&0xF;
                p_device_info->device_id = CTC_CHIP_TSINGMA_AX;
                sal_strcpy(p_device_info->chip_name, "CTC2118");
            }
            break;
        case CTC_CHIP_PROP_SERDES_ID_TO_GPORT:
            {
                ctc_port_serdes_info_t* p_serdes_port = NULL;
                ctc_asw_datapath_serdes_info_t* p_serdes = NULL;
                p_serdes_port = (ctc_port_serdes_info_t*)p_value;
                ret = _ctc_asw_datapath_get_serdes_info(lchip, p_serdes_port->serdes_id, &p_serdes);
                if (0 == ret)
                {
                    p_serdes_port->gport = p_serdes->lport;
                    p_serdes_port->serdes_mode = p_serdes->mode;
                }
            }
            break;
            case CTC_CHIP_PROP_SERDES_LOOPBACK:
            {
                ctc_chip_serdes_loopback_t* p_loopback = NULL;
                ds_t ds;
                uint32 gport = 0;
                uint8 port_num = 0;

                sal_memset(ds, 0, sizeof(ds));
                p_loopback = (ctc_chip_serdes_loopback_t*)p_value;

                ret = _ctc_asw_datapath_get_gport_with_serdes(lchip, p_loopback->serdes_id, &gport, &port_num);
                if (0 == p_loopback->mode)
                {
                    cmd = DRV_IOR(MacTxCtrl_t, DRV_ENTRY_FLAG);
                    ret = ret?ret:DRV_IOCTL(lchip, gport, cmd, &ds);
                    p_loopback->enable = GetMacTxCtrl(V, loopbackEn_f, &ds);
                }
                else
                {
                    cmd = DRV_IOR(MacRxCtrl_t, DRV_ENTRY_FLAG);
                    ret = ret?ret:DRV_IOCTL(lchip, gport, cmd, &ds);
                    p_loopback->enable = GetMacRxCtrl(V, loopbackEn_f, &ds);
                }
            }
            break;
        case CTC_CHIP_PROP_SERDES_PRBS:
            {
                ctc_chip_serdes_prbs_t* p_prbs = (ctc_chip_serdes_prbs_t*)p_value;
                CTC_MAX_VALUE_CHECK_UNLOCK(p_prbs->serdes_id, CTC_ASW_MAX_NORMAL_SERDES_NUM-1);
                switch(p_prbs->mode)
                {
                    case 0: /* 0--Rx */
                        ret = _ctc_asw_datapath_get_serdes_prbs_rx(lchip, p_prbs);
                        break;
                    case 1: /* 1--Tx */
                        ret = _ctc_asw_datapath_get_serdes_prbs_tx(lchip, p_prbs);
                        break;
                    default:
                        ret = CTC_E_INVALID_PARAM;
                        break;
                }
            }
            break;
        case CTC_CHIP_PROP_SERDES_FFE:
            {
                ctc_chip_serdes_ffe_t* p_ffe = (ctc_chip_serdes_ffe_t*)p_value;
                CTC_MAX_VALUE_CHECK_UNLOCK(p_ffe->serdes_id, CTC_ASW_MAX_NORMAL_SERDES_NUM-1);
                ret = _ctc_asw_datapath_get_serdes_ffe(lchip, p_ffe);
            }
            break;
        case CTC_CHIP_PROP_PERI_CLOCK:
            {
                ctc_chip_peri_clock_t* p_clock = (ctc_chip_peri_clock_t*)p_value;
                switch(p_clock->type)
                {
                    case CTC_CHIP_PERI_MDIO_TYPE:
                        ret = _ctc_asw_chip_get_mdio_clock(lchip, &value);
                        p_clock->clock_val = value;
                        break;
                    case CTC_CHIP_PERI_MAC_LED_TYPE:
                        ret =_ctc_asw_chip_get_led_clock(lchip, &value);
                        p_clock->clock_val = value;
                        break;
                    default:
                        ret = CTC_E_INVALID_PARAM;
                        break;
                }
                break;
            }
        case CTC_CHIP_PROP_PHY_MAPPING:
            ret = _ctc_asw_peri_get_phy_mapping(lchip, (ctc_chip_phy_mapping_para_t*)p_value);
            break;
        case CTC_CHIP_MAC_LED_EN:
            ret = _ctc_asw_chip_get_mac_led_en(lchip, (bool *)p_value);
            break;
        case CTC_CHIP_PROP_IO_WR_DIS:
            drv_asw_get_io_wr_dis(lchip, (uint32 *)p_value);
            break;
        case CTC_CHIP_PROP_SERDES_DFE:
            {
                ctc_chip_serdes_cfg_t* p_dfe = (ctc_chip_serdes_cfg_t*)p_value;
                CTC_MAX_VALUE_CHECK_UNLOCK(p_dfe->serdes_id, CTC_ASW_MAX_NORMAL_SERDES_NUM-1);
                CTC_MAX_VALUE_CHECK_UNLOCK(p_dfe->value, (CTC_ASW_MAX_DFE_MODE_NUM-1));
                ret = _ctc_asw_datapath_get_serdes_dfe(lchip, p_dfe);
            }
            break;
        default:
            CTC_API_UNLOCK(lchip);
            return CTC_E_INVALID_PARAM;
    }
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_get_chip_clock(uint8 lchip, uint16* freq)
{
    int32 ret = CTC_E_NONE;

    CTC_PTR_VALID_CHECK(freq);
    CTC_API_LOCK(lchip);
    ret = _ctc_asw_get_chip_clock(lchip, freq);
    CTC_API_UNLOCK(lchip);

    return ret;
}


/**
 @brief phy related api
*/
/**
 @brief set phy to port mapping
*/

int32
ctc_asw_chip_init(uint8 lchip, uint8 lchip_num)
{
    uint32 cmd = 0;
    ds_t ds;
    uint32 start_cnt = 0;
    uint32 value = 0;
    
    sal_mutex_create(&api_mutex[lchip]);
    if (NULL == api_mutex[lchip])
    {
        CTC_ERROR_RETURN(CTC_E_NO_MEMORY);
    }
    sal_mutex_create(&mdio_mutex[lchip]);
    if (NULL == mdio_mutex[lchip])
    {
        sal_mutex_destroy(api_mutex[lchip]);
        CTC_ERROR_RETURN(CTC_E_NO_MEMORY);
    }
    drv_asw_init(lchip);

    /*default set phy port not probe phy sim*/
    sal_memset((uint8*)&chip_master[lchip], 0, sizeof(ctc_asw_chip_master_t));
    sal_memset(&chip_master[lchip].port_phy_shim_idx, CTC_ASW_INVALID_PHY_SHIM_IDX, sizeof(uint8)*CTC_ASW_MAX_PHY_PORT_NUM);
    
roll_start:
    CTC_ERROR_RETURN(_ctc_asw_chip_mdio_init(lchip));

    cmd = DRV_IOR(DeviceId_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &value));
    if ((0 == ((value>>16) & 0xF)) && (0 == start_cnt))
    {
        cmd = DRV_IOR(ResetCtlCpuSub_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip,0,cmd,&ds));
        SetResetCtlCpuSub(V, cfgResetSwitch_f, &ds, 0);
        cmd = DRV_IOW(ResetCtlCpuSub_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip,0,cmd,&ds));

        /*axio inphy_ext_write 4 0xa005 0x4080*/
        SetMdioCfg(V, mdioInDly_f, &ds, 0x1);
        SetMdioCfg(V, mdioMacPre_f, &ds, 0x1f);
        /*config internal phy*/
        SetMdioCfg(V, mdioNetSel_f, &ds, 0x1);
        cmd = DRV_IOW(MdioCfg_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip,0,cmd,&ds));
        /* set mdio operation cmd */
        SetMdioCmd(V, phyAddCmd_f, &ds, 4);
        SetMdioCmd(V, regAddCmd_f, &ds, 0x1e);
        SetMdioCmd(V, opCodeCmd_f, &ds, 1);
        SetMdioCmd(V, dataCmd_f, &ds, 0xa005);
        cmd = DRV_IOW(MdioCmd_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip,0,cmd,&ds));
        /* start write operation */
        SetMdioStart(V, startCmd_f, &ds, 1);
        cmd = DRV_IOW(MdioStart_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip,0,cmd,&ds));

        SetMdioCfg(V, mdioInDly_f, &ds, 0x1);
        SetMdioCfg(V, mdioMacPre_f, &ds, 0x1f);
        /*config internal phy*/
        SetMdioCfg(V, mdioNetSel_f, &ds, 0x1);
        cmd = DRV_IOW(MdioCfg_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip,0,cmd,&ds));
        /* set mdio operation cmd */
        SetMdioCmd(V, phyAddCmd_f, &ds, 4);
        SetMdioCmd(V, regAddCmd_f, &ds, 0x1f);
        SetMdioCmd(V, opCodeCmd_f, &ds, 1);
        SetMdioCmd(V, dataCmd_f, &ds, 0x4080);
        cmd = DRV_IOW(MdioCmd_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip,0,cmd,&ds));
        /* start write operation */
        SetMdioStart(V, startCmd_f, &ds, 1);
        cmd = DRV_IOW(MdioStart_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip,0,cmd,&ds));

        /*axio inphy_ext_write 4 0x27 0x6010*/
        SetMdioCfg(V, mdioInDly_f, &ds, 0x1);
        SetMdioCfg(V, mdioMacPre_f, &ds, 0x1f);
        /*config internal phy*/
        SetMdioCfg(V, mdioNetSel_f, &ds, 0x1);
        cmd = DRV_IOW(MdioCfg_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip,0,cmd,&ds));
        /* set mdio operation cmd */
        SetMdioCmd(V, phyAddCmd_f, &ds, 4);
        SetMdioCmd(V, regAddCmd_f, &ds, 0x1e);
        SetMdioCmd(V, opCodeCmd_f, &ds, 1);
        SetMdioCmd(V, dataCmd_f, &ds, 0x27);
        cmd = DRV_IOW(MdioCmd_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip,0,cmd,&ds));
        /* start write operation */
        SetMdioStart(V, startCmd_f, &ds, 1);
        cmd = DRV_IOW(MdioStart_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip,0,cmd,&ds));

        SetMdioCfg(V, mdioInDly_f, &ds, 0x1);
        SetMdioCfg(V, mdioMacPre_f, &ds, 0x1f);
        /*config internal phy*/
        SetMdioCfg(V, mdioNetSel_f, &ds, 0x1);
        cmd = DRV_IOW(MdioCfg_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip,0,cmd,&ds));
        /* set mdio operation cmd */
        SetMdioCmd(V, phyAddCmd_f, &ds, 4);
        SetMdioCmd(V, regAddCmd_f, &ds, 0x1f);
        SetMdioCmd(V, opCodeCmd_f, &ds, 1);
        SetMdioCmd(V, dataCmd_f, &ds, 0x6010);
        cmd = DRV_IOW(MdioCmd_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip,0,cmd,&ds));
        /* start write operation */
        SetMdioStart(V, startCmd_f, &ds, 1);
        cmd = DRV_IOW(MdioStart_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip,0,cmd,&ds));

        /*axio inphy_ext_write 4 0xa00f 0xf*/
        SetMdioCfg(V, mdioInDly_f, &ds, 0x1);
        SetMdioCfg(V, mdioMacPre_f, &ds, 0x1f);
        /*config internal phy*/
        SetMdioCfg(V, mdioNetSel_f, &ds, 0x1);
        cmd = DRV_IOW(MdioCfg_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip,0,cmd,&ds));
        /* set mdio operation cmd */
        SetMdioCmd(V, phyAddCmd_f, &ds, 4);
        SetMdioCmd(V, regAddCmd_f, &ds, 0x1e);
        SetMdioCmd(V, opCodeCmd_f, &ds, 1);
        SetMdioCmd(V, dataCmd_f, &ds, 0xa00f);
        cmd = DRV_IOW(MdioCmd_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip,0,cmd,&ds));
        /* start write operation */
        SetMdioStart(V, startCmd_f, &ds, 1);
        cmd = DRV_IOW(MdioStart_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip,0,cmd,&ds));

        SetMdioCfg(V, mdioInDly_f, &ds, 0x1);
        SetMdioCfg(V, mdioMacPre_f, &ds, 0x1f);
        /*config internal phy*/
        SetMdioCfg(V, mdioNetSel_f, &ds, 0x1);
        cmd = DRV_IOW(MdioCfg_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip,0,cmd,&ds));
        /* set mdio operation cmd */
        SetMdioCmd(V, phyAddCmd_f, &ds, 4);
        SetMdioCmd(V, regAddCmd_f, &ds, 0x1f);
        SetMdioCmd(V, opCodeCmd_f, &ds, 1);
        SetMdioCmd(V, dataCmd_f, &ds, 0xf);
        cmd = DRV_IOW(MdioCmd_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip,0,cmd,&ds));
        /* start write operation */
        SetMdioStart(V, startCmd_f, &ds, 1);
        cmd = DRV_IOW(MdioStart_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip,0,cmd,&ds));

        sal_task_sleep(50);
        start_cnt ++;
        goto roll_start;
    }
    
    return CTC_E_NONE;
}


int32
ctc_asw_chip_deinit(uint8 lchip)
{
    drv_asw_deinit(lchip);
    sal_mutex_destroy(mdio_mutex[lchip]);
    sal_mutex_destroy(api_mutex[lchip]);

    return CTC_E_NONE;
}

#define ______L3IF_API______

int32
ctc_asw_l3if_set_router_mac(uint8 lchip, mac_addr_t mac_addr)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    HostMac_m host_mac;
    hw_mac_addr_t   hw_mac = {0};

    CTC_API_LOCK(lchip);
    cmd = DRV_IOR(HostMac_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, 0, cmd, &host_mac);
    CTC_ASW_SET_HW_MAC(hw_mac, mac_addr);
    SetHostMac(A, mac_f, &host_mac, hw_mac);
    cmd = DRV_IOW(HostMac_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip, 0, cmd, &host_mac);
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_l3if_get_router_mac(uint8 lchip, mac_addr_t mac_addr)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    HostMac_m host_mac;
    hw_mac_addr_t hw_mac = {0};

    CTC_API_LOCK(lchip);
    cmd = DRV_IOR(HostMac_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, 0, cmd, &host_mac);
    GetHostMac(A, mac_f, &host_mac, hw_mac);
    CTC_ASW_SET_USER_MAC(mac_addr, hw_mac);
    CTC_API_UNLOCK(lchip);

    return ret;
}
